Neb*_*ula 2 c# variables methods lambda
所以我正在与一些LINQ(实体框架)lambda进行斗争,我最终通过将结果存储在变量中来解决这个问题.就像是:
IQueryable<object> DoStuff() { return /* some linq query */; }
void Main()
{
var result = DoStuff();
// (_database is DbContext) == true
// Works fine
_database.Table.Where(x => result.Contains(x.Id));
// Throws "LINQ to Entities does not recognize the method '[...] DoStuff()' method, and this method cannot be translated into a store expression."
_database.Table.Where(x => DoStuff().Contains(x.Id));
}
Run Code Online (Sandbox Code Playgroud)
我能够通过将查询存储在一个单独的变量中来解决我的问题(偶然),但我很好奇为什么这样做?这是延迟执行的事吗?在此之前,我一直认为两个可交换的方法(方法与中间变量用法)用于引用类型,但显然它们不是.
在LINQ to SQL,EF等中,Where()方法中的lambda在执行之前会转换为SQL查询.如果使用自己的方法,则此转换将失败,因为该方法DoStuff()在SQL中是未知的.如果您在LINQ lambda"外部"获得结果,那么SQL查询将使用静态值创建,因此可以正常运行...
当然 - 这是理解lambda表达式发生了什么的问题.
对于LINQ to SQL,EF等,它被转换为表达式树 - 基本上是表示lambda表达式中代码的数据.然后,LINQ提供程序必须将该数据转换为SQL.如何将调用转换DoStuff()为SQL?您不能,因为DoStuff()数据库中不存在,并且提供程序不知道该方法在SQL本身中尝试模拟它的方式.在非常有限的那个方法调用的做工作,有效地硬编码到LINQ提供程序,与翻译成SQL一起.
从理论上讲,一个特定的智能LINQ提供程序可以发现调用DoQuery,分析其中的IL来计算它的作用,并检查它是否理解其中的所有内容,并将其转换为SQL.但是,我不知道任何LINQ提供程序执行此操作,并且我会非常惊讶地看到一个能够可靠地执行它的程序,包括其中的进一步方法调用DoStuff.这将是一项庞大的工作量,你不会希望它在执行时发生.(当然,将它视为概念证明真是太棒了......)
现在,即使使用LINQ to Objects,您的两段代码之间也会有不同的行为.在工作代码中,DoStuff()执行一次,然后结果用于与序列中的每个元素进行比较.在失败的代码中,您将在序列中的每个元素上调用DoStuff()一次.它仍然可以工作,但你可能会不必要地多次执行查询.请注意,此处lambda表达式的转换是不同的 - 编译器将使用委托转换而不是表达式树转换.
在你的特定情况下,可能会有更多的事情发生 - 因为你的方法返回IQueryable<object>,很可能从方法返回的内容甚至还没有作为查询执行 - 但假设它是针对相同数据库的LINQ查询同一个提供程序,LINQ提供程序将"理解"返回DoStuff()的查询DoStufF()并编制一个SQL查询,包括查询部分和使用它Main.查看正在执行的SQL的日志以验证这一点.
| 归档时间: |
|
| 查看次数: |
217 次 |
| 最近记录: |