【问题标题】:Using LinqKit to Apply a Query to a Single Complex Property使用 LinqKit 将查询应用于单个复杂属性
【发布时间】:2015-01-27 22:14:15
【问题描述】:

编辑:在 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 是来自 Entity Framework 的 StructureAnalysis 对象的 IQueryable

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

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

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

...with “参数 't' 未绑定在指定的 LINQ to Entities 查询表达式中。” 等。在此示例中,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,但没有效果,以及以下“解决方案”:

【问题讨论】:

  • 我认为建议的关闭原因无效。
  • @Shoe 提供的代码没有重现问题;关闭的原因是完全有效的。或者您是否能够使用提供的代码重现所描述的问题?
  • @Servy 我不久前更新了 Q 并在 cmets 中向您发送了您的答案。我很确定你现在可以重现它,但如果不能,请告诉我。
  • @Grinn 当前显示的代码没有重现问题。
  • @Servy 显示的代码是在 LINQPad 中执行的完整代码。不过不用担心,因为我已经找到了解决手头问题的方法。

标签: c# linq entity-framework linqpad linqkit


【解决方案1】:

我最终自己找到了解决方案。诀窍是将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();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-12
    • 1970-01-01
    • 2017-09-16
    • 1970-01-01
    • 1970-01-01
    • 2013-08-17
    • 2013-02-05
    • 2021-05-18
    相关资源
    最近更新 更多