【问题标题】:C# method return versus variable in a lambdaC# 方法返回与 lambda 中的变量
【发布时间】:2016-01-09 14:42:04
【问题描述】:

所以我正在与一些 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));
}

我能够通过将查询存储在一个单独的变量中来解决我的问题(偶然),但我很好奇 为什么 有效?这是延迟执行的事情吗?在此之前,我一直认为这两者对于引用类型是可交换的(方法与中间变量的使用),但显然它们不是。

【问题讨论】:

  • 你在打什么?原始代码有什么问题?
  • @YuvalItzchakov 我从引发异常的行开始,不明白为什么。我想我花了两个小时的摆弄和一位同事的帮助才意外地找到了解决方案。
  • 投反对票是因为?

标签: c# variables methods lambda


【解决方案1】:

当然 - 这是了解 lambda 表达式发生了什么的问题。

对于 LINQ to SQL、EF 等,它被转换为 expression tree - 基本上是表示 lambda 表达式中代码的数据。然后,LINQ 提供程序必须将该数据转换为 SQL。如何将调用DoStuff() 转换为SQL?你不能,因为DoStuff() 不存在于数据库中,并且提供者不知道该方法会做什么来尝试在 SQL 本身中模拟它。 do 工作的非常有限的一组方法调用被有效地硬编码到 LINQ 提供程序中,以及转换为 SQL。

理论上,一个特定的智能 LINQ 提供程序可以发现对 DoQuery 的调用,分析其中的 IL 以了解它的作用,并检查它是否理解其中的所有内容,然后转换它到SQL。但是,我不知道有任何 LINQ 提供程序可以做到这一点,我会很惊讶地看到有一个可以可靠地做到这一点,包括DoStuff 中的进一步方法调用。这将是一个庞大的工作量,无论如何你都不希望它在执行时发生。 (当然,将其视为概念证明会很棒......)

现在,即使使用 LINQ to Objects,两段代码之间的行为也会有所不同。在工作代码中,DoStuff() 被执行一次,然后将结果用于与序列中的每个元素进行比较。在失败的代码中,您将在序列中每个元素 调用一次DoStuff()。它仍然可以工作,但您最终可能会不必要地多次执行查询。请注意,这里 lambda 表达式的转换是不同的 - 编译器将使用 delegate 转换而不是表达式树转换。

在您的特定情况下,可能会发生更多事情 - 因为您的方法返回 IQueryable&lt;object&gt;,所以从该方法返回的内容很可能还没有作为查询执行 - 但假设它是一个 LINQ 查询针对具有相同提供程序的相同数据库,LINQ 提供程序将“理解”DoStuff() 返回的查询并制定一个 SQL 查询,包括 DoStufF() 中的查询部分和 Main 中的使用。查看正在执行哪些 SQL 的日志来验证这一点。

【讨论】:

  • 很好的答案(我怎么能期待别的……)!正是我正在寻找的技术细节的数量。我从中得到的是,在另一个 lambda 中使用它们之前,我应该始终将“linq 方法”结果存储在一个单独的变量中。现在,请原谅我,我将阅读表达式树。
【解决方案2】:

在 LINQ to SQL、EF 等中,Where() 方法中的 lambda 在执行之前会转换为 SQL 查询。如果您使用自己的方法,则此转换将失败,因为方法 DoStuff() 在 SQL 中是未知的。如果您在 LINQ lambda “外部”获得结果,则 SQL 查询是使用静态值创建的,因此可以工作...

【讨论】:

  • 我看对了吗?这个答案的得分比乔恩的得分高吗? :\(并不是说这是一个糟糕的答案,远非如此。只是很惊讶,仅此而已)
  • @TimothyGroote 你为什么这么惊讶?
  • 好答案!非常中肯。我一直在寻找有关此问题的更全面的技术背景,因此恐怕 Jon 的回答有我的偏好。我猜还有更糟糕的人会输给我 ;-)
猜你喜欢
  • 1970-01-01
  • 2012-05-17
  • 2018-05-28
  • 2015-12-16
  • 1970-01-01
  • 2020-03-14
  • 1970-01-01
  • 2014-05-12
  • 1970-01-01
相关资源
最近更新 更多