【问题标题】:Why does a variable value have to be modelled as a member access to the closure in an expression tree?为什么必须将变量值建模为表达式树中对闭包的成员访问?
【发布时间】:2017-05-17 13:02:55
【问题描述】:

当我在我们的应用程序中将表达式编写为 lambda 表达式时,我通常可以使用以下构造1

dbContext.Contents<MyEntity>()

dbContext 属于自定义类。) 不知何故,Linq1Entities/Entity Framework 理解这意味着我是 SELECTing 表中匹配 MyEntity 的项目。

现在,我正在通过 System.Linq.Expressions 类构造一个表达式。 我试图像这样复制上面的片段:

Expression.Call(Expression.Constant(dbContext), contentsMethod)

contentsMethod之前已经通过反射的方式初始化为合适的MethodInfo

很遗憾,这不起作用。 实体框架抱怨它无法将dbContext 对象转换为 SQL。

我已经构建了一个与我想要的 lambda 表达式类似的表达式,并在调试器中查看了生成的表达式树。 有趣的是,dbContext 不是常量,而是被建模为似乎是闭包对象的member access

这是为什么呢?为什么局部变量 dbContext 由成员访问表达式中的闭包表示,为什么它不作为常量值工作?在我的情况下,dbContext 是封闭方法的参数是否重要?

我的问题是不是如何解决这个问题。 我已经这样做了,将上面显示的片段作为一个额外的 lambda 表达式引入,它的主体与我手动构建的表达式相关联。


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

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

【问题讨论】:

  • dbContext 是一个由不同表组成的数据库对象。 A Select 查询表。这些表由具有不同数据类型的列组成。通常转换发生在列的字段类型上。
  • 你能举一个更完整的例子来说明你如何使用dbContext.Contents&lt;MyEntity&gt;()吗?问题似乎很不清楚,至少对我来说。我知道你有 dbContext 参数,你将它传递给一些 lambda,它被捕获并且它的访问变成了闭包对象的成员访问。
  • @Evk:我添加了一个脚注,其中包含一个简短且匿名但完整的表达式,其中包含指示的片段。
  • 我实际上无法重现这个。我使用Expression.Constant(dbContext)(确切地说是Expression.PropertyOrField(Expression.Constant(dbContext), "NameOfMyDbSetProperty")))构建了一个表达式,代表您的确切Any 查询,它可以正常工作而不会受到EF 方面的抱怨。
  • @Evk 实际上它适用于属性/字段,但不适用于方法调用(肯定适用于像Set&lt;T&gt; 这样的通用实例方法)

标签: c# entity-framework linq lambda linq-expressions


【解决方案1】:

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

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

【讨论】:

  • 是的,但是这种情况下的结论是什么? EF 只能在 dbContext 是其他成员时处理它,而不是直接作为常量值提供?
  • @O.R.Mapper 那或者你在你的情况下做了其他不同的事情,它不知道如何映射。
  • @O.R.Mapper 这就是确切的结论。表达式树翻译的整个技巧是翻译器识别/处理什么类型的表达式。正如 Servy 在他的回答中提到的那样,显然 EF 查询翻译器无法识别/处理您的案例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-12
  • 1970-01-01
  • 2017-05-26
  • 2012-07-22
  • 2011-08-22
  • 2013-04-05
相关资源
最近更新 更多