2012-10-15 11 views
5

Próbuję zrozumieć pewne implikacje wydajności LINQ z darmowego ebooka przez RedGate ftp://support.red-gate.com/ebooks/under-the-hood-of-net-memory-management-part1.pdfCzy można wywołać metodę nazwaną w wywołaniu Gdzie?

Na stronie 157-158 w tej książce, stworzyli następujący przykład.

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

Następnie ponownie uwzględniono część wyrażenia lamda w następującej funkcji.

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

W końcu użyli tej funkcji w następujący sposób.

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

podstawie tego, co ja zbadane dotąd jej nie możliwe do uruchomienia tej kwerendy LINQ jako LINQ nie będzie w stanie rozpoznać metodę i nie można przełożyć na wyrażenie sklepu. Zastanawiam się, czy ten przykład jest zły i po prostu niemożliwy do uruchomienia, czy też po prostu mam trudności ze zrozumieniem, jak zasymulować ten problem?

Odpowiedz

3

Jak powiedział casperOne, nie można tego zrobić za pomocą funkcji. Ta odpowiedź jest sposobem na zrobienie tego, co należy zrobić (ponowne użycie filtra gdzie).

Możesz utworzyć Expression gdzieś, gdzie możesz uzyskać dostęp, a następnie użyj go ponownie.

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

Potem go użyć później:

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

Jest to pełny kod używam z tym:

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 jest ObjectContext w projekcie .
entities.SomeNeatEntities to ObjectSet<SomeNeatEntity>.

+0

To jest złe i nie zadziała, ponieważ nie jest to wyrażenie lambda i nie może zostać ocenione przez dostawcę zapytań. – casperOne

+0

Dosłownie mam to działa przeciwko instalacji EF mam. – Gromer

+3

Jeśli działa, filtrujesz * na kliencie *, a wywołanie 'Gdzie' ocenia wyniki z' IEnumerable 'i * not * tłumacząc filtr po stronie serwera. Pamiętaj, że '' IQueryable 'pochodzi z' IEnumerable ', więc wszystkie metody rozszerzeń na' IEumerumeracie 'będą działać na' IQueryable 'i nie zawsze jest oczywiste, gdzie nastąpi przejście. – casperOne

8

Masz rację, nie można go wywołać przez LINQ-to-Entities w taki sposób, w jaki jest wyświetlany.

Jedynym sposobem mogłoby być wykorzystane w LINQ-Podmiotów jest:

+0

Używanie "AsExpandable()" LINQKita to kolejna alternatywa, w której można używać metod wyrażeń, które można przetłumaczyć na SQL. – Ocelot20

+0

@casperOne: Odnośnie komentarza do najechania na Gdzie w VS.NET na Gdzie jest wywołane t i h, w jaki sposób określa, kiedy zadzwonić Gdzie z IEnumerable i kiedy zadzwonić Gdzie z IQueryable? –

+0

@palmsnow Zasadniczo typ wnioskowania określa najlepsze dopasowanie. W tym szczególnym przypadku, ponieważ parametr jest 'Func ' a nie 'Wyrażenie >' nie może się równać z 'Queryable.Where' (który przyjmuje wyrażenie), tylko' Enumerable.Where '(który bierze delegata). – casperOne

Powiązane problemy