2011-01-31 2 views
9

J'ai une méthode:L'utilisation d'une expression lambda transmise à une méthode ralentit-elle une requête Entity Framework?

public static void GetObjects() 
{ 
    using(MyContext context = new MyContext()) 
    { 
     var objects = context.Bars.Where(b => b.Prop1 != null) 
         .Select(b => new MyObject{Prop = b.Prop1, Name = b.Name}) 
         .ToList(); 
     foreach(var object in objects) 
     { 
      // do something with the object 
     } 
    } 
} 

Je remaniée avec la méthode pour la rendre plus générale pour que je puisse passer dans un Func afin que je puisse préciser la déclaration where et quels sont les biens de la table Bars est attribué, à MyObject.Prop comme ceci:

public static void GetObjectsV2(Func<Bar, bool> whereFunc, Func<Bar, string> selectPropFunc) 
{ 
    using(MyContext context = new MyContext()) 
    { 
     var objects = context.Bars.Where(whereFunc) 
         .Select(b => new MyObject{Prop = selectPropFunc(b), Name = b.Name}) 
         .ToList(); 
     foreach(var object in objects) 
     { 
      // do something with the object 
     } 
    } 
} 

GetObjectsV2 semble fonctionner beaucoup plus lent que GetObjects. Y a-t-il des raisons pour lesquelles cela affecterait la performance, et si oui, y a-t-il des moyens de contourner cela tout en gardant la fonction flexible?

Répondre

16

La raison pour laquelle il s'exécute plus lentement est que vous passez un Func<Bar, bool> qui force le contexte à récupérer TOUS les barres, puis à exécuter le Func sur le jeu de résultats renvoyé. Une façon de faire cette course mieux est de passer Expression<Func<Bar, bool>>

Mettre que tous ensemble aura les conséquences suivantes:

public static void GetObjectsV2(Expression<Func<Bar, bool>> whereFunc, Expression<Func<Bar, string>> selectPropFunc) 
{ 
    using(MyContext context = new MyContext()) 
    { 
     var objects = context.Bars.Where(whereFunc) 
         .Select(selectPropFunc) 
         .ToList(); 
     foreach(var object in objects) 
     { 
      // do something with the object 
     } 
    } 
} 
+0

Merci beaucoup pour la réponse rapide! – aubreyrhodes

5

Comme I discovered in my own question, .Where(o => whereFunc(o)) n'est pas la même chose que dans le .Where(whereFunc) Entity Framework.

Le premier, .Where(Expression<Func<Bar, bool>>) fonctionne comme n'importe quel autre appel linq, en ajoutant simplement l'expression à l'arbre d'expression. Dans le deuxième cas, .Where(Func<Bar, bool>>), il compilera et évaluera l'appel linq (qui est jusqu'à présent juste context.Bars) avant d'appliquer le prédicat whereFunc.


Donc, pour répondre à votre question, le second est beaucoup plus lent, car il tire la totalité de la table Bars en mémoire avant de faire quoi que ce soit avec lui. L'utilisation .Where(o => whereFunc(o)) devrait plutôt fixer que

(ou, comme Mark suggère, changer le type de whereFunc à Expression<Func<Bar, bool>>, qui Func<Bar, bool> est implicitement convertible)

Questions connexes