C# 为什么必须将变量值建模为表达式树中访问闭包的成员?

C# 为什么必须将变量值建模为表达式树中访问闭包的成员?,c#,entity-framework,linq,lambda,linq-expressions,C#,Entity Framework,Linq,Lambda,Linq Expressions,当我在应用程序中编写表达式作为lambda表达式时,通常可以使用以下构造函数1: contentsMethod之前已通过反射方式初始化为相应的MethodInfo 不幸的是,这不起作用。 实体框架抱怨无法将dbContext对象转换为SQL 我已经构建了一个类似的lambda表达式,并在调试器中查看了结果表达式树。 有趣的是,dbContext被建模为似乎是闭包对象的成员访问,而不是常量 为什么?为什么局部变量dbContext在表达式中由访问闭包的成员表示,为什么它不能作为常量值工作?在我的例

当我在应用程序中编写表达式作为lambda表达式时,通常可以使用以下构造函数1:

contentsMethod
之前已通过反射方式初始化为相应的
MethodInfo

不幸的是,这不起作用。 实体框架抱怨无法将
dbContext
对象转换为SQL

我已经构建了一个类似的lambda表达式,并在调试器中查看了结果表达式树。 有趣的是,
dbContext
被建模为似乎是闭包对象的
成员访问
,而不是常量

为什么?为什么局部变量
dbContext
在表达式中由访问闭包的成员表示,为什么它不能作为常量值工作?在我的例子中,
dbContext
是封闭方法的参数,这有关系吗?

我的问题不是如何解决这个问题。 我已经这样做了,通过引入上面所示的片段作为一个额外的lambda表达式,其主体被绑定到我手动构建的表达式中


1:下面的表达式是如何使用该片段的示例:

dbContext.Contents<MyEntity1>().Where(e1 => dbContext.Contents<MyEntity2>().Any(e2 => e1.Name == e2.Key))
dbContext.Contents().Where(e1=>dbContext.Contents().Any(e2=>e1.Name==e2.Key))

dbContext
被建模为对closure对象的访问,因为定义它的lambda正在关闭该变量。它没有使用一个常量值,而是在另一个值上闭合,所以这就是它在
表达式中所表示的。如果它做了其他事情,它就不能正确地表示lambda


当EF说它不能将
表达式
转换为SQL时,它只是说代码的作者没有预料到给定的表达式,也没有创建该模式到SQL的映射;他们根本没有料到会有人这样做(或者不知道如何将其映射到SQL,或者不能,或者没有时间添加该功能,不管情况如何)。

dbContext是一个由不同表组成的数据库对象。选择查询表。这些表由具有不同数据类型的列组成。通常,转换发生在列的字段类型上。您能否提供一个更完整的示例,说明如何使用
dbContext.Contents()
?这个问题看起来很不清楚,至少对我来说是这样。我知道您有dbContext参数,您将它传递给某个lambda,它被捕获,它的访问权限成为closure对象的成员访问权限。@Evk:我添加了一个脚注,其中包含一个简短的匿名但完整的表达式,其中包含指定的片段。我实际上无法复制此脚注。我使用
expression.Constant(dbContext)
(确切地说是
expression.PropertyOrField(expression.Constant(dbContext),“nameofMyBSetProperty”)
)构建了一个表达式,表示您确切的
任何
查询,它工作正常,不会引起EF方面的抱怨。@Evk实际上它适用于属性/字段,但不适用于方法调用(对于像
Set
这样的泛型实例方法,这是肯定的),是的,但在这种情况下,结论是什么?EF只能在它是其他对象的成员时处理
dbContext
,而不是直接作为常量值提供?@O.R.Mapper,或者您做了其他不同的事情,它不知道如何映射。@O.R.Mapper这就是确切的结论。表达式树翻译的整个技巧是翻译器识别/处理哪种类型的表达式。正如Servy在回答中提到的,显然您的案例未被EF查询翻译人员识别/处理。
Expression.Call(Expression.Constant(dbContext), contentsMethod)
dbContext.Contents<MyEntity1>().Where(e1 => dbContext.Contents<MyEntity2>().Any(e2 => e1.Name == e2.Key))