0

我试图让我的头脑围绕组合表达式,环顾四周,应该可以做我想做的事情,但我正在努力。

我有一个Expression<Func<class, dynamic>>定义了我最终针对我的 EF 上下文运行的选择,我class从中选择数据的表在哪里。例如:

Expression<Func<foo, dynamic>> expression = foo => new
{
   RecordExists = foo.bar.Exists,
   RecordHasPaid = foo.bar.Amount != null && foo.bar.Amount > 0
}

// run the expression against the database and get the results...
var results = context.foo.Select(expression);

我想要做的是然后将该表达式中的通用逻辑提取到静态“帮助”样式表达式中,例如,我可以重复使用,而不是在我的第一个表达式中包含这一行

RecordHasPaid = foo.bar.Amount != null && foo.bar.Amount > 0

我可以有一个可重用的表达式,存储在一个可重用的类中,例如ExpressionHelper,然后我可以将其插入到我的第一个表达式中:

public static Expression<Func<bar, bool>> BarHasPaid(bar foobar)
{
   return b => b.Amount != null && b.Amount > 0;
}

变成:

Expression<Func<foo, dynamic>> expression = foo => new
{
   RecordExists = foo.bar.Exists,
   RecordHasPaid = ExpressionHelper.BarHasPaid(foo.bar)
}

// run the expression against the database and get the results...
var results = context.foo.Select(expression);

请注意,我向这个表达式传递了一个与我的外部表达式不同的参数(希望我可以是通用的)。

听起来不错,编译得很好,但是 - 当我开始运行 .Select 时,我得到了可怕的错误:

LINQ to Entities 无法识别方法 'System.Linq.Expressions.Expression1[System.Func2[bar,System.Boolean]] BarHasPaid(bar)' 方法,并且该方法无法转换为存储表达式。

我理解发生这种情况的原因(至少我认为是这样),因为我的方法未知,因此无法翻译成 SQL,此外,我的表达式无法转换为对 EF 有意义的表达式树,因为我本质上是在使用两种不同的表达方式,它不知道如何将它们变成有意义的东西。

我尝试了各种方法,将诸如此处的表达式组合在一起,不幸的是,当您有两个表达式而不是另一个表达式的一个表达式时,这似乎可以工作。

我也尝试过使用此处提到的自定义 ExpressionVisitor 实现包装/解包(我最终确实让它编译得很好,但我得到了同样的错误)

我还尝试了许多其他类似的答案,并尝试使用 LinqKit 来Expand表达我的表达方式,并且设置我的上下文AsExpandable也无济于事。到目前为止,我的所有尝试都导致了上述错误,或者在尝试组合 usingLambdaExpression.Lambda来编译我的组合表达式时导致了这个错误:

从范围“”引用的类型变量“foo”但未定义

foo我认为这是被抛出的,因为在我的外部表达式中使用的变量,在我的表达式Expression<Func<foo, dynamic>>中不存在,Expression<Func<bar, bool>>因为当它们组合时产生的表达式没有意义。

不幸的是,我认为我对我正在尝试做的事情的理解不够深入,所以我在下一步转向哪里时遇到了一些死胡同。任何关于这是否可能和/或如何实现它的建议将不胜感激。

编辑:我使用 Rextester 创建了两个示例项目,这是工作示例这就是导致错误的原因- 使用此在线工具,您实际上可以看到应该运行什么 EF,但由于没有 EF 可以针对错误运行它在那次测试期间实际上并没有发生。

4

1 回答 1

-1

你的代码

Expression<Func<foo, dynamic>> expression = foo => new
{ RecordExists = foo.bar.Exists,
  RecordHasPaid = ExpressionHelper.BarHasPaid(foo.bar)
}

不返回所需的结果。类型RecordHasPaidExpression<Func<bar, bool>>不仅仅是bool。很明显,EF 对此感到困惑。

基本上,您希望在表达式主体中调用另一个表达式,而不是返回 lambda 表达式。不幸的是,AFAIK 使用 LINQ 语法是不可能的。

但是如果你处理表达式树,你就可以完成这项工作。看看这里: Combining two lambda expressions in c#

处理表达式树缺乏美观和类型安全性,但它是一把强大的剑。可惜编译器拒绝支持表达式树的全套特性。缺少 Lambda 调用以及循环。

于 2018-08-03T21:38:07.130 回答