5

tôi cần phải lọc một danh sách các tài liệu bằng cách chuyển chúng vào một bộ lọc tùy chỉnh mà tôi đang đấu tranh để xây dựng động sử dụng một vòng lặp foreach:Xây dựng một vị tùy chỉnh để hoạt động như một bộ lọc bằng cách sử dụng foreach vòng lặp

var mainPredicate = PredicateBuilder.True<Document>(); 

// mainPredicate is combined to other filters successfully here ... 

var innerPredicate = PredicateBuilder.False<Document>(); 
foreach (var period in periods) 
{ 
    var p = period; 
    Expression<Func<Document, bool>> inPeriod = 
     d => d.Date >= p.DateFrom && d.Date <= p.DateTo; 

    innerPredicate = innerPredicate.Or(d => inPeriod.Invoke(d)); 
} 

mainPredicate = mainPredicate.And(innerPredicate); 

dòng cuối cùng này:

documents = this.ObjectSet.AsExpandable().Where(mainPredicate).ToList(); 

Ném ngoại lệ này:

Tham số 'd' không bị ràng buộc trong biểu thức truy vấn LINQ to Entities được chỉ định.

Bất cứ ai cũng biết tại sao tôi bị ngoại lệ này? Tôi không hiểu nơi mà các 'd' tham số tôi đang đi đến phương pháp InPeriod bị mất. Tôi không biết những gì còn thiếu để làm việc này. Mã của tôi giống như nhiều ví dụ khác hoạt động hoàn hảo. Bất kỳ thông tin lý thuyết bổ sung lý thuyết nào về cách gọi các biểu thức và cách nó hoạt động phía sau hậu trường đều được chào đón.

+0

Điều gì xảy ra nếu bạn thực hiện 'mainPredicate.Expand(). Biên dịch(). Gọi (someDocument)'? Bạn có chắc chắn vấn đề không phải ở một nơi nào khác (mã của bạn có vẻ ổn với tôi) không? – svick

+0

Với gợi ý của bạn, tôi đã sửa đổi dòng cuối cùng để nó trông như sau: 'documentEntries = this.ObjectSet.AsExpandable(). Where (de => mainPredicate.Expand(). Compile(). Invoke (de)). ToList (); nhưng nó ném: LINQ to Entities không nhận ra phương thức 'Boolean Invoke (Remabec.PM.Tarification.DocumentEntry)' phương pháp, và phương pháp này không thể được dịch sang một biểu thức cửa hàng. –

+0

Vâng, điều đó sẽ không hoạt động và đó không phải là ý tôi. Bạn có thể tự mình thực thi mã của tôi không? – svick

Trả lời

1

Cuối cùng, tôi đã tìm thấy một cách để tránh kết hợp nhiều vị từ để biểu thức chính cây.

Cho rằng mỗi vị đại diện cho một bộ lọc khác nhau và tôi muốn trận chung kết, kết hợp bộ lọc là một loạt các phải-được-tôn trọng điều kiện, chúng ta có thể nói rằng mỗi người trong số các vị đã trở lại đúng cho vị từ cuối cùng để trả về true.

Để làm việc đó, các vị từ phải được kết hợp với AND. Vì vậy, kết quả truy vấn SQL phải trông như thế này:

predicate1 AND predicate2 AND predicate3 ...

Cách tốt hơn để kết hợp các vị từ với AND là chuỗi Where nhà khai thác truy vấn để truy vấn cuối cùng, như thế này:

var documents = this.ObjectSet.AsExpandable() 
    .Where(mainPredicate) 
    .Where(otherPredicate) 
    .Where(yetAnotherPredicate) 
    .ToList(); 

Truy vấn SQL kết quả sẽ kết hợp từng vị từ này với AND. Đó chỉ là những gì tôi muốn làm.

Dễ dàng hơn việc tự mình lấy ra một cây biểu thức.

2

Tôi không hiểu lý do tại sao bạn làm điều này:

innerPredicate = innerPredicate.Or(d => inPeriod.Invoke(d)); 

Khi bạn chỉ có thể tránh được những Invoke hoàn toàn, như thế này:

innerPredicate = innerPredicate.Or(inPeriod); 

này nên làm việc hoàn toàn tốt đẹp.


BTW, tôi có cảm giác có lỗi với LINQKit tại đây (trừ khi có một số tài liệu gợi ý rằng nó không hỗ trợ tình huống này).

Khi tôi cố gắng mã này tương tự:

Expression<Func<int, bool>> first = p1 => p1 > 4; 
Expression<Func<int, bool>> second = p2 => p2 < 2; 

// Expand is similar to AsExpandable, except it works on 
// expressions, not queryables. 
var composite = first.Or(d => second.Invoke(d)) 
        .Expand(); 

... LINQKit tạo ra khái niệm tổng hợp sau đây:

p1 => ((p1 > 4) OrElse (d < 2)) // what on earth is d? 

... mà thực sự có tham số ràng buộc d (NodeType = Tham số, Tên = 'd').

Dodging các Invoke với first.Or(second).Expand() tạo ra hoàn toàn hợp lý:

p1 => ((p1 > 4) OrElse (p1 < 2)) // much better now... 
+0

'innerPredicate.Or (inPeriod.Invoke)' sẽ không biên dịch. Tôi nghĩ bạn có nghĩa là 'innerPredicate.Or (inPeriod)'. – svick

+0

@svick: Ồ, lỗi đánh máy! Tôi nói tránh 'Invoke' sau đó không xóa nó từ bản sao-mì ống bản thân mình. Cảm ơn. – Ani

+0

Nếu tôi không rõ ràng gọi biểu thức (như bạn đã đề xuất: 'innerPredicate.Or (inPeriod))' Tôi nhận được: __The tham số 'f' không bị ràng buộc trong biểu thức truy vấn LINQ to Entities được chỉ định .__ –

0

tôi sử dụng các phương pháp khuyến nông:

public static class Extensions 
{ 
    public static Expression<Func<T, bool>> OrElse<T>(this Expression<Func<T, bool>> source, Expression<Func<T, bool>> predicate) 
    { 
     InvocationExpression invokedExpression = Expression.Invoke(predicate, source.Parameters.Cast<Expression>()); 
     return Expression.Lambda<Func<T, bool>>(Expression.OrElse(source.Body, invokedExpression), source.Parameters); 
    } 

    public static Expression<Func<T, bool>> AndAlso<T>(this Expression<Func<T, bool>> source, Expression<Func<T, bool>> predicate) 
    { 
     InvocationExpression invokedExpression = Expression.Invoke(predicate, source.Parameters.Cast<Expression>()); 
     return Expression.Lambda<Func<T, bool>>(Expression.AndAlso(source.Body, invokedExpression), source.Parameters); 
    } 

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