1180 votes

De Retour IEnumerable<T> vs IQueryable<T>

Quelle est la différence entre le retour IQueryable<T> vs IEnumerable<T>?

IQueryable<Customer> custs = from c in db.Customers
where c.City == "<City>"
select c;

IEnumerable<Customer> custs = from c in db.Customers
where c.City == "<City>"
select c;

Seront tous deux mis à exécution différée et quand doit-on être préférée à une autre?

1911voto

driis Points 70872

Oui, les deux vous donnera l'exécution différée.

La différence est que IQueryable<T> est une interface qui permet de LINQ-to-SQL (LINQ.-à quelque chose de vraiment. Donc, si vous affiner votre requête sur un IQueryable<T>, cette requête sera exécutée dans la base de données, si possible.

Pour l'interface IEnumerable<T> les cas, il sera LINQ-to-objet, ce qui signifie que tous les objets correspondant à la requête d'origine doit être chargé en mémoire à partir de la base de données.

Dans le code:

IQueryable<Customer> custs = ...;
// Later on...
var goldCustomers = custs.Where(c => c.IsGold);

Ce code s'execute SQL pour sélectionner uniquement les clients d'or. Le code suivant, d'autre part, l'exécution de la requête d'origine dans la base de données, puis en filtrant les non-clients d'or dans la mémoire:

IEnumerable<Customer> custs = ...;
// Later on...
var goldCustomers = custs.Where(c => c.IsGold);

C'est tout à fait une grande différence, et de travailler sur IQueryable<T> peut dans de nombreux cas, vous sauver de retour trop grand nombre de lignes de la base de données. Un autre exemple est en train de faire de la pagination: Si vous utilisez Prendre et Sauter sur IQueryable, vous aurez seulement le nombre de lignes demandés; le faire que sur un IEnumerable<T>, toutes vos lignes pour être chargé dans la mémoire.

93voto

Kasper Roma Points 102

Nous allons illustrer la différence à l'aide de sql server profiler pour voir la grandeur de IQueryable,

lorsque nous exécutez le code suivant:

MarketDevEntities db = new MarketDevEntities();

IEnumerable<WebLog> first = db.WebLogs;
var second = first.Where(c => c.DurationSeconds > 10);
var third = second.Where(c => c.WebLogID > 100);
var result = third.Where(c => c.EmailAddress.Length > 11);

Console.Write(result.First().UserName);

Dans le générateur de profils SQL, nous trouvons une commande égale à:

"SELECT * FROM [dbo].[WebLog]"

C'environ 90 secondes pour exécuter un bloc de code à l'encontre du Blog la table de qui a 1 million de record.

Donc, tous les enregistrements de la table chargée en mémoire, comme les objets, puis avec chaque .Où (), ce sera une autre filtre dans la mémoire à l'égard de ces objets.

Lorsque nous utilisons IQueryable au lieu de IEnumerable dans l'exemple ci-dessus(Deuxième ligne):

Dans le générateur de profils SQL, nous trouvons une commande égale à:

"SELECT TOP 1 * FROM [dbo].[WebLog] WHERE [DurationSeconds] > 10 AND [WebLogID] > 100 AND LEN([EmailAddress]) > 11"

C'environ 4 secondes pour exécuter ce bloc de code à l'aide d' IQueryable.

IQueryable ont une propriété appelée Expression stocker de l'arbre de l'expression qui, au départ, formé lorsque nous avons utilisé l' result dans notre exemple(ce qui est appelé l'exécution différée), à la fin de cette Expression sera convertie à la requête SQL à exécuter sur le moteur de base de données.

63voto

Justin Niessner Points 144953

Les deux vous donnera l'exécution différée, oui.

Pour ce qui est préférée à une autre, cela dépend de votre source de données sous-jacente.

Retour d'un IEnumerable automatiquement la force de l'exécution pour utiliser LINQ to Objects pour interroger votre collection.

Retour d'un IQueryable (qui implémente l'interface IEnumerable, par la voie) fournit la fonctionnalité supplémentaire pour traduire votre requête dans quelque chose qui pourrait mieux fonctionner sur la source sous-jacent (LINQ to SQL, LINQ to XML, etc.).

38voto

sebastianmehler Points 285

En Termes Généraux, je recommanderais:

Pour revenir IQueryable si vous souhaitez activer le Développeur à l'aide de votre Méthode pour affiner la Requête de retour avant de s'exécuter.

Si vous voulez transporter seulement un ensemble d'Objets à dénombrer plus de il suffit de prendre IEnumerable.

Image un IQueryable comme ce qu'elle est une "Requête" pour les Données (que vous pouvez préciser si vous voulez)

Un IEnumerable est un Ensemble d'Objets (qui a déjà été recievied ou a été créé) sur lequel vous pouvez IEnumerable.

26voto

AJS Points 131

En général, vous souhaitez conserver l'original de type statique de la requête jusqu'à ce qu'il questions.

Pour cette raison, vous pouvez définir la variable 'var' à la place des IQueryable<> ou IEnumerable<> , et vous savez que vous n'êtes pas changer le type.

Si vous commencez avec un IQueryable<>, vous souhaitez généralement de le garder comme un IQueryable<> jusqu'à il y a quelques raison impérieuse de le changer. La raison pour cela est que vous souhaitez donner à la requête du processeur autant d'informations que possible. Par exemple, si vous n'utilisez que 10 résultats (que vous avez appelés Take(10)), alors vous voulez SQL Server à savoir à ce sujet afin qu'il puisse optimiser ses plans de requête et de vous envoyer seulement les données que vous allez utiliser.

Une raison valable pour changer le type d' IQueryable<> de IEnumerable<> peut-être que vous appelez une extension de la fonction que la mise en œuvre de l' IQueryable<> dans votre objet particulier ne peut pas les gérer ou les poignées de façon inefficace. Dans ce cas, vous pourriez souhaiter pour convertir le texte en IEnumerable<> (par l'affectation à une variable de type IEnumerable<> ou en utilisant l' AsEnumerable méthode d'extension par exemple), de sorte que les fonctions d'extension vous appeler à la fin ceux de l' Enumerable classe à la place de l' Queryable classe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X