2012-02-21 32 views
5

Trước tiên, tôi phải nói rằng tôi đã đọc một số bài về điều này tại StackOverflow nhưng tôi không thể có được kết quả mong muốn.LINQ to SQL kết hợp hai biểu thức <Func <T, bool>> ("where khoản") với và/hoặc

Hãy để tôi giải thích ngữ cảnh (đơn giản): Tôi đang sử dụng LINQ to SQL để truy vấn khách hàng với các lần truy cập gần đây đến cửa hàng và (tùy chọn) chỉ nhận những người có số tiền thanh toán nhất định. Giả sử tôi có một mô hình với khách hàng, thăm và các lớp học thanh toán.

Vì vậy, tập trung vào sự biểu hiện Where, tôi đang cố gắng này:

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); 
} 

Phương pháp filter.And là một phương pháp khuyến nông, khuyến cáo tại diễn đàn này, bên dưới, bạn có thể xem định nghĩa:

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); 
} 

Tuy nhiên, điều này không hiệu quả với tôi như mong đợi và kết quả không được lọc theo số tiền thanh toán. Không có lỗi với dữ liệu hoặc mô hình LINQ-to-sql vì mã này hoạt động tốt:

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

Tuy nhiên, tôi không muốn sử dụng mã cuối cùng bởi vì tôi có một số tình huống phức tạp hơn, trong đó tôi cần phải xây dựng biểu thức lọc theo từng bước với kết hợp 'và/hoặc' của mỗi phần.

PD: Tôi là một "ADO.Net DataSets" guy cố gắng tìm hiểu Linq-to-SQL và sớm Entity Framework, tôi hy vọng sẽ hữu ích cho cộng đồng StackOverflow sớm.

+3

p.s., bạn nên sử dụng phương thức 'Expression.AndAlso()' để tạo biểu thức logic AND ('&&'). 'Expression.And()' tạo ra biểu thức bitwise AND ('&'). –

Trả lời

3

Bạn không chỉ định kết quả của And nhập vào bất kỳ thứ gì.

Tôi cho rằng phần tương ứng của mã của bạn nên đọc như sau:

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

Cái này là của bạn (hoặc SO là như bạn đề cập) And chức năng lợi nhuận biểu thức có chứa sự kết hợp của hai biểu thức. Nó không thay đổi đối tượng mà nó được gọi.

+0

ouch ... cảm ơn! –

+0

@FranCD Bạn được chào đón. Nhân tiện, tôi lấy sự tự do của mình để trả lời câu hỏi của bạn về phiên bản gốc, để những khách truy cập tiếp tục xem mã gốc thực sự là gì. Nếu không, câu trả lời dưới đây không có ý nghĩa. – Krizz

0

Check-out LinqKit và đó là lớp PredicateBuilder: http://www.albahari.com/nutshell/predicatebuilder.aspx

+0

Và thực hiện tôi sử dụng là từ lớp PredicateBuilder, và không hoạt động ... Đâu là sai lầm? –

+0

@FranCD có lỗi trong việc sử dụng của bạn, hãy xem câu trả lời của tôi. – Krizz

1

Vấn đề là dòng này:

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

Phương pháp And trả về một đại biểu mà bạn đã không giao cho bất cứ điều gì. Hãy thử điều này:

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

Chỉ cần làm rõ, And là một phương thức có hai biểu thức và kết hợp logic của chúng để tạo biểu thức mới. Nó không thay đổi biểu thức nó được thực hiện trên, nhưng trả về biểu thức mới dưới dạng giá trị trả về. Vì vậy, trong mã của bạn, bạn đang gọi filter.And(...) nhưng không làm bất cứ điều gì với giá trị trả lại, vì vậy filter vẫn tham chiếu biểu thức lambda gốc.

Các vấn đề liên quan