54

我需要构建一个动态过滤器,并且我想继续使用实体。由于这个原因,我想使用来自 albahari 的 PredicateBuilder。

我创建了以下代码:

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

当我运行代码时,只有 1 个不是日期过滤器的过滤器。所以只填充了内部谓词。执行谓词时,出现以下错误。

参数“f”未绑定在指定的 LINQ to Entities 查询表达式中。

在寻找答案时,我发现了以下页面。但这已经在 LINQKit 中实现了。

有没有其他人遇到过这个错误并且知道如何解决它?

4

2 回答 2

122

我遇到了同样的错误,问题似乎是当我使用 PredicateBuilder 制作的谓词又由 PredicateBuilder 制作的其他谓词组成时

例如 (A OR B) AND (X OR Y),其中一个构建器创建 A OR B,一个构建器创建 X OR Y,第三个构建器将它们组合在一起。

只有一级谓词 AsExpandable 工作正常,当引入多个级别时,我得到了同样的错误。

我找不到任何帮助,但通过一些试验和错误,我能够让事情正常进行。每次我调用谓词时,我都会使用 Expand 扩展方法。

下面是一些代码,为简单起见将其删减:

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 是一个 IQueryable,它已经调用了 AsExpandable,ConstructOptionNotMatchPredicate 返回一个 Expression。

一旦我们克服了错误,我们当然能够在运行时针对实体框架构建复杂的过滤器。

编辑:

由于人们仍在评论和投票,我认为它仍然有用,所以我分享另一个修复。基本上我已经停止使用 LinqKit,它的谓词构建器支持具有相同 API 但不需要扩展调用的通用谓词构建器,非常值得一试。

于 2010-06-02T11:39:36.720 回答
44

我收到了这个错误,Mant101 的解释给了我答案,但您可能正在寻找一个导致问题的更简单的示例:

// 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!
}

希望这可以帮助!:-)

于 2012-07-04T22:39:03.060 回答