2011-01-31 4 views
9

Ho un metodo:L'uso di un'espressione lambda passata in un metodo rallenta una query di 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 
     } 
    } 
} 

ho riscritta il metodo per renderlo più generale, in modo che io possa passare in un Func in modo che possa specificare l'istruzione where e quale proprietà dalla tabella Bars viene assegnato a MyObject.Prop in questo modo:

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 sembra funzionare molto più lento rispetto GetObjects. Ci sono dei motivi per cui ciò influirebbe sulle prestazioni e, in tal caso, ci sono dei modi per aggirare questo problema mantenendo la funzione flessibile?

risposta

16

La ragione è in esecuzione più lenta è perché si sta passando in una Func<Bar, bool> che costringe il contesto per retrive tutti i bar e quindi eseguire il Func sul set di risultati restituiti. Un modo per rendere questa corsa migliore è passare in Expression<Func<Bar, bool>>

Mettendo tutto insieme porteranno al seguente:

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

Grazie mille per la risposta rapida! – aubreyrhodes

5

Come I discovered in my own question, .Where(o => whereFunc(o)) non è la stessa .Where(whereFunc) in Entity Framework.

Il primo, .Where(Expression<Func<Bar, bool>>) funziona come qualsiasi altra chiamata di linq, semplicemente aggiungendo l'espressione all'albero delle espressioni.

Nel secondo caso, .Where(Func<Bar, bool>>), sarà compilato e valutare la chiamata LINQ (che finora è solo context.Bars) prima di applicare la whereFunc predicato.


Quindi, per rispondere alla tua domanda, la seconda è molto più lento, perché sta tirando l'intera tabella Bars in memoria prima di fare qualsiasi cosa con esso. Utilizzando .Where(o => whereFunc(o)) invece dovrebbe risolvere che

(o, come suggerisce Mark, modificare il tipo di whereFunc a Expression<Func<Bar, bool>>, che Func<Bar, bool> è implicitamente convertibile)