À quoi sert IQueryable
dans le contexte de LINQ?
Est-il utilisé pour développer des méthodes d'extension ou à toute autre fin?
la source
À quoi sert IQueryable
dans le contexte de LINQ?
Est-il utilisé pour développer des méthodes d'extension ou à toute autre fin?
La réponse de Marc Gravell est très complète, mais j'ai pensé ajouter quelque chose à ce sujet du point de vue de l'utilisateur également ...
La principale différence, du point de vue d'un utilisateur, est que, lorsque vous utilisez IQueryable<T>
(avec un fournisseur qui prend correctement en charge les choses), vous pouvez économiser beaucoup de ressources.
Par exemple, si vous travaillez sur une base de données distante, avec de nombreux systèmes ORM, vous avez la possibilité de récupérer les données d'une table de deux manières, l'une qui renvoie IEnumerable<T>
et l'autre qui renvoie un IQueryable<T>
. Supposons, par exemple, que vous ayez une table Produits et que vous souhaitiez obtenir tous les produits dont le coût est> 25 $.
Si tu fais:
IEnumerable<Product> products = myORM.GetProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);
Ce qui se passe ici, c'est que la base de données charge tous les produits et les transmet à votre programme. Votre programme filtre ensuite les données. En substance, la base de données fait un SELECT * FROM Products
et vous renvoie TOUS les produits.
En IQueryable<T>
revanche, avec le bon fournisseur, vous pouvez faire:
IQueryable<Product> products = myORM.GetQueryableProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);
Le code a la même apparence, mais la différence ici est que le SQL exécuté le sera SELECT * FROM Products WHERE Cost >= 25
.
De votre POV en tant que développeur, cela se ressemble. Cependant, du point de vue des performances, vous ne pouvez renvoyer que 2 enregistrements sur le réseau au lieu de 20 000 ....
IQueryable<Product>
- serait spécifique à votre ORM ou référentiel, etc.foreach
ou appelezToList()
), vous ne frappez pas réellement la base de données.En substance, son travail est très similaire à
IEnumerable<T>
- pour représenter une source de données interrogeable - la différence étant que les différentes méthodes LINQ (onQueryable
) peuvent être plus spécifiques, pour construire la requête en utilisant desExpression
arbres plutôt que des délégués (ce qui est ce quiEnumerable
utilise).Les arborescences d'expression peuvent être inspectées par le fournisseur LINQ de votre choix et transformées en une requête réelle - bien qu'il s'agisse d'un art noir en soi.
C'est vraiment dû au
ElementType
,Expression
etProvider
- mais en réalité, vous avez rarement besoin de vous en soucier en tant qu'utilisateur . Seul un implémenteur LINQ a besoin de connaître les détails sanglants.Re commentaires; Je ne sais pas trop ce que vous voulez à titre d'exemple, mais considérez LINQ-to-SQL; l'objet central ici est un
DataContext
, qui représente notre enveloppe de base de données. Cela a généralement une propriété par table (par exemple,Customers
) et une table implémenteIQueryable<Customer>
. Mais nous n'utilisons pas beaucoup cela directement; considérer:cela devient (par le compilateur C #):
qui est à nouveau interprété (par le compilateur C #) comme:
Il est important de noter que les méthodes statiques sur les
Queryable
arborescences d'expression take, qui - plutôt que l'IL normal, sont compilées en un modèle objet. Par exemple - en regardant simplement le "Où", cela nous donne quelque chose de comparable à:Le compilateur n'a-t-il pas fait beaucoup pour nous? Ce modèle d'objet peut être déchiré, inspecté pour ce qu'il signifie et reconstitué par le générateur TSQL - donnant quelque chose comme:
(la chaîne peut finir en paramètre; je ne me souviens pas)
Rien de tout cela ne serait possible si nous venions d'utiliser un délégué. Et c'est le point de / : il fournit le point d'entrée pour l' utilisation des arbres d'expression.
Queryable
IQueryable<T>
Tout cela est très complexe, c'est donc un bon travail que le compilateur le rend agréable et facile pour nous.
Pour plus d'informations, consultez « C # en profondeur » ou « LINQ en action », qui offrent tous deux une couverture de ces sujets.
la source
Bien que Reed Copsey et Marc Gravell aient déjà décrit à propos
IQueryable
(et aussiIEnumerable
) assez, mJ veux ajouter un peu plus ici en fournissant un petit exemple surIQueryable
etIEnumerable
autant d'utilisateurs l'ont demandéExemple : j'ai créé deux tables dans la base de données
La clé primaire (
PersonId
) de la tableEmployee
est également une clé forgein (personid
) de la tablePerson
Ensuite, j'ai ajouté le modèle d'entité ado.net dans mon application et créé ci-dessous la classe de service
ils contiennent le même linq. Il a appelé
program.cs
comme défini ci-dessousLa sortie est la même pour les deux évidemment
La question est donc quelle est / où est la différence? Il ne semble pas y avoir de différence non? Vraiment!!
Jetons un coup d'œil aux requêtes SQL générées et exécutées par l'entité framwork 5 au cours de cette période
Partie d'exécution IQueryable
Partie d'exécution IEnumerable
Script commun pour les deux parties d'exécution
Vous avez donc quelques questions maintenant, laissez-moi deviner celles-ci et essayez d'y répondre
Pourquoi différents scripts sont-ils générés pour le même résultat?
Permet de découvrir quelques points ici,
toutes les requêtes ont une partie commune
WHERE [Extent1].[PersonId] IN (0,1,2,3)
Pourquoi? Parce que la fonction
IQueryable<Employee> GetEmployeeAndPersonDetailIQueryable
etIEnumerable<Employee> GetEmployeeAndPersonDetailIEnumerable
deSomeServiceClass
contient une ligne commune dans les requêtes linqwhere employeesToCollect.Contains(e.PersonId)
Que pourquoi la
AND (N'M' = [Extent1].[Gender])
partie est manquante dans laIEnumerable
partie d'exécution, alors que dans les deux fonctions, nous avons utiliséWhere(i => i.Gender == "M") in
program.cs`Quel encadrement d'entité fait lorsqu'un
IQueryable
méthode est appelée, elle prend une instruction linq écrite à l'intérieur de la méthode et essaie de savoir si plus d'expressions linq sont définies sur l'ensemble de résultats, elle rassemble ensuite toutes les requêtes linq définies jusqu'à ce que le résultat doive être récupéré et construit un sql plus approprié requête à exécuter.Il offre de nombreux avantages comme,
comme ici dans l'exemple, le serveur SQL n'a renvoyé à l'application que deux lignes après l'exécution de IQueryable` mais a renvoyé TROIS lignes pour la requête IEnumerable pourquoi?
En cas de
IEnumerable
méthode, le framework d'entité a pris l'instruction linq écrite à l'intérieur de la méthode et construit la requête sql lorsque le résultat doit être récupéré. il n'inclut pas la partie rest linq pour construire la requête sql. Comme ici, aucun filtrage n'est effectué dans le serveur SQL sur la colonnegender
.Mais les sorties sont les mêmes? Parce que 'IEnumerable filtre le résultat plus loin au niveau de l'application après avoir récupéré le résultat du serveur SQL
Alors, que doit-on choisir? Personnellement, je préfère définir le résultat de la fonction car,
IQueryable<T>
car il présente de nombreux avantagesIEnumerable
, vous pouvez joindre deux ou plusieurs fonctions IQueryable, qui génèrent un script plus spécifique pour le serveur SQL.Ici, dans l'exemple, vous pouvez voir un
IQueryable Query(IQueryableQuery2)
génère un script plus spécifique queIEnumerable query(IEnumerableQuery2)
ce qui est beaucoup plus acceptable à mon point de vue.la source
Il permet de poursuivre les requêtes plus loin sur la ligne. Si cela dépassait une limite de service, par exemple, l'utilisateur de cet objet IQueryable serait autorisé à en faire plus.
Par exemple, si vous utilisiez le chargement différé avec nhibernate, cela pourrait entraîner le chargement du graphique quand / si nécessaire.
la source