2010-12-10 5 views
6

Quel est l'avantage d'écrire un fournisseur LINQ personnalisé plutôt que d'écrire une classe simple qui implémente IEnumerable?Pourquoi écrire un fournisseur LINQ personnalisé?

Par exemple, ce quesiton montre Linq2Excel:

var book = new ExcelQueryFactory(@"C:\Users.xls"); 
var administrators = from x in book.Worksheet<User>() 
        where x.Role == "Administrator" 
        select x; 

Mais quel est l'avantage sur la mise en œuvre "naïve" comme IEnumerable?

+0

Je ne sais pas pourquoi linq-to-excel profite de IQueryable, mais il y a des cas où le code est beaucoup plus rapide. – CodesInChaos

Répondre

11

Le but d'un fournisseur de Linq est de "traduire" les arbres d'expression Linq (qui sont construits derrière les coulisses d'une requête) dans le langage de requête natif de la source de données. Dans les cas où les données sont déjà en mémoire, vous n'avez pas besoin d'un fournisseur Linq; Linq 2 Objects est très bien. Cependant, si vous utilisez Linq pour parler à un magasin de données externe comme un SGBD ou un nuage, c'est absolument essentiel. Le principe de base de toute structure d'interrogation est que le moteur de la source de données doit faire le plus de travail possible et ne renvoyer que les données dont le client a besoin. Cela est dû au fait que la source de données est supposée savoir le mieux comment gérer les données qu'elle stocke et parce que le transport de données sur le réseau est relativement coûteux en termes de temps et doit donc être minimisé. Maintenant, en réalité, cette deuxième partie est "retourner seulement les données demandées par le client"; le serveur ne peut lire l'esprit de votre programme et sait de quoi il a vraiment besoin; il ne peut que donner ce qu'on lui demande. Voici où un fournisseur Linq intelligent souffle absolument une implémentation "naïve". En utilisant le côté IQueryable de Linq, qui génère des arbres d'expression, un fournisseur Linq peut traduire l'arbre d'expression en une instruction SQL que le SGBD utilisera pour renvoyer les enregistrements demandés par le client dans l'instruction Linq. Une implémentation naïve nécessiterait de récupérer TOUS les enregistrements en utilisant une instruction SQL large, afin de fournir une liste d'objets en mémoire au client, puis tout le travail de filtrage, de groupage, de tri, etc. est effectué par le client. Par exemple, supposons que vous utilisiez Linq pour obtenir un enregistrement d'une table dans le DB à l'aide de sa clé primaire. Un fournisseur Linq peut traduire dataSource.Query<MyObject>().Where(x=>x.Id == 1234).FirstOrDefault() dans "SELECT TOP 1 * de MyObjectTable WHERE Id = 1234". Cela renvoie zéro ou un enregistrements.Une implémentation "naïve" enverrait probablement au serveur la requête "SELECT * FROM MyObjectTable", puis utiliserait le côté IEnumerable de Linq (qui fonctionne sur les classes en mémoire) pour faire le filtrage. Dans une déclaration, vous vous attendez à produire des résultats 0-1 sur une table avec 10 millions d'enregistrements, lesquels d'entre vous pourraient faire le travail plus rapidement (ou même travailler du tout, sans manquer de mémoire)?

7

Vous n'avez pas besoin d'écrire un fournisseur LINQ si vous souhaitez uniquement utiliser la fonctionnalité LINQ-to-Objects (c'est-à-dire foreach -like), qui fonctionne principalement avec les listes en mémoire.

besoin d'écrire un fournisseur LINQ si vous voulez analyser l'arbre d'expression d'une requête afin de la traduire en quelque chose d'autre, comme SQL. L'ExcelQueryFactory que vous avez mentionné semble fonctionner avec une connexion OLEDB par exemple. Cela signifie peut-être qu'il n'a pas besoin de charger tout le fichier Excel en mémoire lors de l'interrogation de ses données.

3

En performance générale. Si vous avez une sorte d'index, vous pouvez faire une requête beaucoup plus rapidement que ce qui est possible sur un simple IEnumerable<T>. Linq-To-Sql est un bon exemple pour cela. Ici, vous transformez l'instruction linq en une autre pour que le serveur SQL la comprenne. Donc, le serveur va faire le filtrage, la commande, ... en utilisant les index et n'a pas besoin d'envoyer la table entière au client qui le fait ensuite avec linq-to-objects.

Mais il y a des cas simples où il peut être utile aussi:

Si vous avez un indice d'arbre sur la propery Time alors une requête de gamme comme .Where(x=>(x.Time>=now)&&(x.Time<=tomorrow)) peut être optimisé beaucoup, et n'a pas besoin d'itérer chaque élément de l'énumérable.

1

LINQ fournira une exécution différée autant que possible pour améliorer les performances.

IEnumurable <> et IQueryable <> fournira totalement différentes implémentations de programme. IQueryable donnera une requête native en construisant dynamiquement l'arbre d'expression qui fournit de bonnes performances en effet alors IEnumurable.

http://msdn.microsoft.com/en-us/vcsharp/ff963710.aspx

si nous ne sommes pas sûrs que nous pouvons utiliser var mot-clé et dynamiquement initialiserons un type le plus approprié.

Questions connexes