使用 LinqKit 将查询应用于单个复杂属性



编辑:在LinqPad的帮助下,我设法将我的代码减少到最小公分母。

我有一个返回复杂 LinqKit 谓词的方法。期望的结果是能够在我需要执行此查询时重用此方法。它在针对这些实体的IQueryable集合的 Where 子句中工作正常,但是当我将此实体作为对象的单个属性时,我一生都无法弄清楚如何使用此谓词,并且想使用谓词来查询该实体的其他属性。

给你一个简化的例子来说明我的意思。

// Note: .Includes removed for brevity's sake.
var task = Tasks.First(t => t.QaConfigTaskId == 2);
var predicate = PredicateBuilder.True<Task>();
// Ensure that the task's own properties match.
predicate = predicate.And(t => t.TaskType == task.TaskType &&
      t.Description == task.Description &&
      t.PreTreatment == task.PreTreatment &&
      t.Treatment == task.Treatment);
var structureAnalysis = task.StructureAnalysis;
var query = PredicateBuilder.True<StructureAnalysis>();
query = query.And(analysis =>
        // The names match
        analysis.Name == structureAnalysis.Name &&
        // We have the same # of goals so they must all match.
        analysis.Goals.Count == structureAnalysis.Goals.Count
    );
predicate = predicate.And(t => query.Invoke(t.StructureAnalysis));

这将正常工作:

StructureAnalyses.AsExpandable().Where(query).Dump();

。假设StructureAnalyses是实体框架中我的StructureAnalysis对象的IQueryable

但是,假设我想获取任务,使用相关的结构分析进行过滤。我怎么能做这样的事情?请记住,实际上,query是由可重用函数构建的,而predicate是由调用它的单独函数构建的,因此我不能简单地合并这两个查询。

当我尝试执行查询时,它可以编译但失败:

Tasks.AsExpandable().Where(predicate).Dump();

。与"参数't'未绑定在指定的 LINQ 到实体查询表达式中"等。在此示例中,Tasks 是一个 IQueryable,其中包含数据库中所有Task类型实体。

我也尝试更改此行:

        predicate = predicate.And(t => query.Invoke(t.StructureAnalysis));

。自:

        compiled = query.Compile();
        predicate = predicate.And(t => compiled(t.StructureAnalysis));

这也编译但失败,"无法将类型'System.Linq.Expressions.FieldExpression'的对象转换为类型'System.Linq.Expressions.LambdaExpression'",这是可以理解的。

我还尝试在querycompiled上调用Expand,但没有效果,以及以下"解决方案":

  • 这个似乎不完整(Utility未定义):https://stackoverflow.com/questions/26105570/linqkit-the-parameter-was-not-bound-in-the-specified-linq-to-entities-query-e
  • 这个只是说,"这不可能做到",我拒绝相信:实体框架代码第一 4.3/相关表的 LINQKit 谓词

我最终自己找到了解决方案。诀窍是将query的调用包装在访问该属性的另一个谓词中,然后在调用该谓词时扩展该谓词。因此,对于我尝试在单个StructureAnalysis上调用查询的示例,我的代码现在如下所示:

// Note: .Includes removed for brevity's sake.
var task = Tasks.First(t => t.QaConfigTaskId == 2);
var predicate = PredicateBuilder.True<Task>();
// Ensure that the task's own properties match.
predicate = predicate.And(t => t.TaskType == task.TaskType &&
      t.Description == task.Description &&
      t.PreTreatment == task.PreTreatment &&
      t.Treatment == task.Treatment);

var structureAnalysis = task.StructureAnalysis;
var query = PredicateBuilder.True<StructureAnalysis>();
query = query.And(analysis =>
        // The names match
        analysis.Name == structureAnalysis.Name &&
        // We have the same # of goals so they must all match.
        analysis.Goals.Count == structureAnalysis.Goals.Count
    );
//// HERE'S WHAT'S NEW ////
Expression<Func<Task, bool>> subPredicate = t => query.Invoke(t.StructureAnalysis);
predicate = predicate.And(subPredicate.Expand());
Tasks.AsExpandable().Where(predicate).Dump();

最新更新