2010-06-01 17 views
54

Tôi cần xây dựng bộ lọc động và tôi muốn tiếp tục sử dụng các thực thể. Vì lý do này tôi muốn sử dụng PredicateBuilder từ albahari.C# Thực thể PredicateBuilder: Tham số 'f' không bị ràng buộc trong biểu thức truy vấn LINQ to Entities được chỉ định

Tôi tạo ra đoạn mã sau:

var invoerDatums = PredicateBuilder.True<OnderzoeksVragen>(); 
var inner = PredicateBuilder.False<OnderzoeksVragen>(); 

foreach (var filter in set.RapportInvoerFilter.ToList()) 
{ 
    if(filter.IsDate) 
    { 
     var date = DateTime.Parse(filter.Waarde); 
     invoerDatums = invoerDatums.Or(o => o.Van >= date && o.Tot <= date); 
    } 
    else 
    { 
     string temp = filter.Waarde; 
     inner = inner.Or(o => o.OnderzoekType == temp); 
    } 
} 

invoerDatums = invoerDatums.And(inner); 
var onderzoeksVragen = entities.OnderzoeksVragen 
           .AsExpandable() 
           .Where(invoerDatums) 
           .ToList(); 

Khi tôi chạy mã chỉ có 1 bộ lọc mà không phải là một bộ lọc ngày. Vì vậy, chỉ có vị từ bên trong được lấp đầy. Khi biến vị ngữ được thực hiện, tôi nhận được lỗi sau.

Tham số 'f' không bị ràng buộc trong LINQ to Entities định truy vấn biểu.

Trong khi tìm kiếm câu trả lời tôi đã tìm thấy page sau đây. Nhưng điều này đã được triển khai trong LINQKit.

Có ai khác gặp phải lỗi này và biết cách giải quyết không?

Trả lời

121

tôi chạy qua những lỗi tương tự, vấn đề này dường như là khi tôi đã có các vị từ được thực hiện với PredicateBuilder rằng đã lần lượt chiếm các vị khác thực hiện với PredicateBuilder

ví dụ (A HOẶC B) VÀ (X HOẶC Y) trong đó một người xây dựng tạo ra A HOẶC B, người tạo ra X OR Y và một AND thứ ba cùng nhau.

Chỉ với một mức độ các vị từ AsExpandable hoạt động tốt, khi có nhiều hơn một cấp đã được giới thiệu, tôi gặp lỗi tương tự.

Tôi không thể tìm thấy bất kỳ trợ giúp nào nhưng thông qua một số bản dùng thử và lỗi, tôi đã có thể làm mọi thứ hoạt động. Mỗi lần tôi gọi một biến vị ngữ, tôi đã theo nó bằng phương pháp mở rộng Mở rộng.

Dưới đây là một chút của mã này, cắt giảm vì đơn giản:

public static IQueryable<Submission> AddOptionFilter(
    this IQueryable<Submission> query, 
    IEnumerable<IGrouping<int, int>> options) 
{ 
    var predicate = options.Aggregate(
     PredicateBuilder.False<Submission>(), 
     (accumulator, optionIds) => accumulator.Or(ConstructOptionMatchPredicate(optionIds).Expand())); 
     query = query.Where(predicate.Expand());    
    return query; 
} 

Query là một IQueryable mà đã có AsExpandable gọi, ConstructOptionNotMatchPredicate trả về một biểu thức.

Khi chúng tôi vượt qua lỗi, chúng tôi chắc chắn có thể xây dựng các bộ lọc phức tạp trong thời gian chạy dựa vào khung pháp nhân.

Edit:

Kể từ khi mọi người vẫn đang bình luận về và lên bỏ phiếu này, tôi cho rằng nó vẫn còn hữu ích vì vậy tôi đang chia sẻ sửa chữa khác. Về cơ bản tôi đã ngừng sử dụng LinqKit và nó là người xây dựng vị ngữ có lợi cho điều này Universal Predicate Builder có cùng API nhưng không cần mở rộng cuộc gọi, cũng có giá trị kiểm tra.

+0

Tôi cũng phải xóa cuộc gọi đến AsExpandable() khỏi đối tượng IQueryable ban đầu của mình. –

+2

Câu trả lời hay, nhưng gây hiểu lầm. Câu trả lời của BloodBaz là câu trả lời chính xác hơn đơn giản hơn – Mick

44

Tôi đã nhận lỗi này và giải thích Mant101 đã cho tôi câu trả lời, nhưng bạn có thể tìm kiếm một ví dụ đơn giản gây ra vấn đề:

// This predicate is the 1st predicate builder 
var predicate = PredicateBuilder.True<Widget>(); 

// and I am adding more predicates to it (all no problem here) 
predicate = predicate.And(c => c.ColumnA == 1); 
predicate = predicate.And(c => c.ColumnB > 32); 
predicate = predicate.And(c => c.ColumnC == 73); 

// Now I want to add another "AND" predicate which actually comprises 
// of a whole list of sub-"OR" predicates 
if(keywords.Length > 0) 
{ 
    // NOTICE: Here I am starting off a brand new 2nd predicate builder.... 
    // (I'm not "AND"ing it to the existing one (yet)) 
    var subpredicate = PredicateBuilder.False<Widget>(); 

    foreach(string s in keywords) 
    { 
     string t = s; // s is part of enumerable so need to make a copy of it 
     subpredicate = subpredicate.Or(c => c.Name.Contains(t)); 
    } 

    // This is the "gotcha" bit... ANDing the independent 
    // sub-predicate to the 1st one.... 

    // If done like this, you will FAIL! 
// predicate = predicate.And(subpredicate); // FAIL at runtime! 

    // To correct it, you must do this... 
    predicate = predicate.And(subpredicate.Expand()); // OK at runtime! 
} 

Hope this helps! :-)