2012-02-21 8 views
5

Po pierwsze, muszę powiedzieć, że przeczytałem kilka postów na ten temat w StackOverflow, ale nie mogę uzyskać pożądanego rezultatu.Linq-to-SQL łączące dwa wyrażenia <Func <T, bool>> ("gdzie klauzula") z i/lub

Pozwolę sobie wyjaśnić kontekst (uproszczony): używam Linq-to-SQL do zapytania klientów o ostatnie wizyty w sklepie i (opcjonalnie) dostaję tylko tych z pewną ilością płatności. Załóżmy, że mam model z klientami, wizytami i klasami płatności.

Więc, koncentrując się na ekspresji Where, próbuję to:

Expression<Func<Entityes.Clients, bool>> filter = null; 

filter = c => 
      c.Visits.Any(v => v.VisitDate > DateTime.Now.Date.AddMonths(-(int)visitsSince)); 


if (minPayment.HasValue && minPayment.Value > 0) 
{ 
    filter.And(
       c => c.Payments.Sum(p => p.Quantity) > minPayment.Value); 
} 

Sposób filter.And jest metoda rozszerzenie, zalecana na tym forum, poniżej można zobaczyć definicję:

public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expression1, 
              Expression<Func<T, bool>> expression2) 
{ 
    InvocationExpression invokedExpression = 
     Expression.Invoke(expression2, expression1.Parameters.Cast<Expression>()); 

    return Expression.Lambda<Func<T, bool>> 
     (Expression.And(expression1.Body, invokedExpression), expression1.Parameters); 
} 

Nie działa to jednak zgodnie z oczekiwaniami, a wyniki nie są filtrowane według kwoty płatności. Nie ma błędu w danych lub modelu LINQ-SQL, ponieważ ten kod działa poprawnie:

filter = c => 
      c.Visits.Any(v => v.VisitDate > DateTime.Now.Date.AddMonths(-(int)visitsSince))) 
      && c => c.Payments.Sum(p => p.Quantity) > minPayment.Value; 

Jednak nie chcę używać ostatniego kodu bo mam jakieś bardziej skomplikowane scenariusze, w których muszę buduj wyrażenie filtru krok po kroku za pomocą kombinacji "i/lub" każdej części.

PD: Jestem facetem "ADO.Net DataSets" próbującym nauczyć się Linq-SQL i wkrótce Entity Framework, mam nadzieję, że wkrótce będę przydatny dla społeczności StackOverflow.

+3

p.s., powinieneś używać metody 'Expression.AndAlso()' do generowania logicznego wyrażenia AND ('&&'). 'Expression.And()' generuje bitowe wyrażenie AND ('&'). –

Odpowiedz

3

Nie przypisujesz wyniku do niczego.

Przypuszczam odpowiednia część kodu należy odczytać następująco:

if (minPayment.HasValue && minPayment.Value > 0) 
{ 
    filter = filter.And(
      c => c.Payments.Sum(p => p.Quantity) > minPayment.Value); 
} 

Rzeczą jest to, że (tak jest, jak wspomniano) And funkcja powraca wyrażenie zawierające koniunkcję dwóch wypowiedzi. Nie zmienia obiektu, na który jest wywoływany.

+0

ouch ... dzięki! –

+0

@FranCD Nie ma za co. Przy okazji, pozwoliłem sobie na wycofanie pytania do oryginalnej wersji, aby inni użytkownicy mogli zobaczyć, jaki był oryginalny oryginalny kod. W przeciwnym razie poniższe odpowiedzi nie mają sensu. – Krizz

1

Problemem jest to linia:

filter.And(c => c.Payments.Sum(p => p.Quantity) > minPayment.Value); 

Sposób And zwraca innego delegata, które nie zostały przypisane do niczego. Spróbuj tego:

filter = filter.And(c => c.Payments.Sum(p => p.Quantity) > minPayment.Value); 

Właśnie w celu wyjaśnienia, And to metoda, która trwa dwa wyrażenia i łączy ich logikę, aby utworzyć nowy wyraz. Nie zmienia to wyrażenia, w którym jest wykonywane, ale zwraca nowe wyrażenie jako wartość zwracaną. Więc w twoim kodzie dzwonisz pod numer filter.And(...), ale nie robisz nic z wartością zwracaną, więc filter nadal odwołuje się do pierwotnego wyrażenia lambda.

Powiązane problemy