2012-10-15 8 views
5

Ich versuche, von RedGate ftp://support.red-gate.com/ebooks/under-the-hood-of-net-memory-management-part1.pdfIst es möglich, benannte Methode innerhalb eines Anrufs zu Where?

Auf Seite 157-158 in diesem Buch einige Performance-Auswirkungen von Linq von diesem kostenlosen E-Book zu verstehen, schufen sie beispielsweise folgende.

Order[] pastDueAccounts = null; 
DateTimedueDate = DateTime.Today.AddDays(-7); 
using(varcontext = new Context())  
{ 
    pastDueAccounts = context.Accounts.Where(account => account.DueDate < dueDate).ToArray(); 
} 

Sie dann Teil der Lambda-Ausdruck in die folgende Funktion neu berechnet.

public bool PastDueAccount(Account account) 
{ 
    return account.DueDate < DateTime.Today.AddDays(-7); 
} 

Schließlich verwendeten sie diese Funktion wie folgt.

Order[] pastDueAccounts = null; 
using(varcontext = new Context()) 
{ 
    pastDueAccounts = context.Accounts.Where(account => PastDueAccount(account)).ToArray(); 
} 

Nach dem, was ich bisher erforscht, es ist nicht möglich, diese Linq-Abfrage als LINQ ausgeführt wird, das Verfahren nicht erkennen kann und nicht in einen Laden Ausdruck übersetzen werden. Ich frage mich, ob dieses Beispiel falsch ist und einfach nicht ausgeführt werden kann oder ob es mir nur schwer fällt, mich darüber zu informieren, wie man dieses Problem simuliert?

Antwort

3

Wie caperOne sagte, können Sie das mit einer Funktion nicht machen. Mit dieser Antwort können Sie das tun, was Sie tun müssen (einen Wo-Filter wiederverwenden).

Sie können ein Expression irgendwo Sie zugreifen können, dann wiederverwenden.

System.Linq.Expressions.Expression<Func<Account, bool>> pastDueAccountFunc = account => account.DueDate < System.Data.Objects.EntityFunctions.AddDays(DateTime.Now, -7);

Dann um es später:

var pastDueAccounts = context.Accounts.Where(pastDueAccountFunc);

Dies ist der vollständige Code, den ich mit diesem bin mit:

System.Linq.Expressions.Expression<Func<SomeNeatEntity, bool>> func = x => x.DateCreated < System.Data.Objects.EntityFunctions.AddDays(DateTime.Now, -7); 

var entities = new MyEntities(); 

var t = entities.SomeNeatEntities.Where(func); 
Console.WriteLine(t.Count()); 

var h = entities.SomeNeatEntities.Where(x => x.SomeField != null).Where(func); 
Console.WriteLine(h.Count()); 

MyEntities ist die ObjectContext im Projekt .
entities.SomeNeatEntities ist ObjectSet<SomeNeatEntity>.

+0

Dies ist falsch und wird nicht funktionieren, da dies kein Lambda-Ausdruck ist und nicht vom Abfrageanbieter ausgewertet werden kann. – casperOne

+0

Ich habe buchstäblich das funktioniert gegen ein EF-Setup, das ich habe. – Gromer

+3

Wenn es funktioniert, filtern Sie * auf dem Client * und der Aufruf von 'Where' bewertet die Ergebnisse von IEnumerable ' und * not * übersetzt den Filter auf die Serverseite. Denken Sie daran, 'IQueryable ' leitet sich von 'IEnumerable ' ab, so dass alle Erweiterungsmethoden auf 'IEnumerable ' auf 'IQueryable ' funktionieren und es nicht immer offensichtlich ist, wo der Übergang auftritt. – casperOne

8

Sie haben Recht, dies wäre nicht in der Lage, von LINQ-to-Entities so aufgerufen zu werden, wie es angezeigt wird.

Der einzige Weg, um es in LINQ-to-Entities verwendet werden könnte, ist:

  • das Äquivalent der Funktion auf der Serverseite erstellen.
  • Map the function in the model entsprechend, so dass es den Anruf richtig übersetzt.
+0

Mit LINQKit 'AsExpandable()' ist eine andere Alternative, wo Sie Ausdrucksmethoden verwenden können, die in SQL übersetzt werden können. – Ocelot20

+0

@casperOne: In Bezug auf Ihren Kommentar zum Schweben über Wo in VS.NET auf Wo für t und h aufgerufen, wie bestimmt es, wann Where mit IEnumerable aufrufen und wann wo mit IQueryable aufrufen? –

+0

@palmsnow Grundsätzlich Typ Inferenz bestimmt die beste Passform. In diesem speziellen Fall, da der Parameter ein 'Func ' ist und nicht ein 'Ausdruck >' kann es nicht mit 'Queryable.Where' (die einen Ausdruck nimmt), nur' Enumerable.Where' (die nimmt einen Delegierten). – casperOne

Verwandte Themen