在另一个Expression <func <t,tu =“” >>

时间:2018-08-03 16:39:26

标签: c# lambda expression func linqkit

我正在努力使表达式组合起来,环顾四周,应该有可能做我想做的事情,但是我很挣扎。

我有一个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);

我想做的就是将表达式中的通用逻辑提取到我可以重用的静态“ helper”样式表达式中,例如,而不是在第一个表达式中包含此行

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有意义的表达式树,因为我本质上是在彼此之间使用两个不同的表达式,并且不知道如何将它们变成有意义的东西。

我已经尝试了多种方法,结合了here之类的表达式,不幸的是,当您有两个表达式,而不是一个表达式在内部 另一个表达式时,

我还尝试过使用here中提到的自定义ExpressionVisitors来实现包装/展开(我最终确实可以很好地编译它,但是得到了相同的错误)

我也尝试了许多其他类似的答案,并尝试使用LinqKit来Expand我的表情,并使用AsExpandable设置我的上下文无济于事。到目前为止,我所有的尝试都导致了以上错误,或者在尝试使用LambdaExpression.Lambda进行合并的组合表达式进行合并时导致了该错误:

  

从作用域''引用的类型的变量'foo',但未定义

我认为这是因为在我的外部表达式foo中使用的变量Expression<Func<foo, dynamic>>在我的表达式Expression<Func<bar, bool>>中不存在,因为将它们组合后的结果表达式没有任何意义。

不幸的是,我认为我对自己想做的事情没有足够深入的了解,因此我对于下一步的路途已陷入僵局。任何关于这是否可能和/或如何实现的建议,将不胜感激。

编辑:我已经使用Rextester创建了两个示例项目this is the working examplethis is what causes the error-使用此在线工具,您实际上可以看到应该运行的EF,但是由于没有EF可以针对它运行测试期间实际上并没有发生错误。

1 个答案:

答案 0 :(得分:-1)

您的代码

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

不返回期望的结果。 RecordHasPaid的类型为Expression<Func<bar, bool>> ,而不仅仅是bool。显然,EF对此感到困惑。

基本上,您想调用表达式内的另一个表达式,而不是返回lambda表达式。 不幸的是,对于AFAIK来说,使用LINQ语法是不可能的。

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

与表情树打交道缺乏美感和类型安全性,但这是一把强大的剑。可惜编译器拒绝支持表达式树的全部功能。 Lambda调用以及循环都丢失了。