gpt4 book ai didi

linq-to-entities - 为什么EF throw "NotSupportedException: The method ' First'只能作为最终查询操作”

转载 作者:行者123 更新时间:2023-12-04 08:31:54 24 4
gpt4 key购买 nike

int[] ids1 = { 1, 2, 3 };
int[] ids2 = { 1, 5, 6 };

var result = from a in ids1
where a == ids2.First()
select a;
foreach (var item in result) ; //ok


var employees = from c in context.Employees.
where c.EmployeeID == ids1.First()
select c;
foreach (var item in employees); // NotSupportedException

尝试调用 ids1.First 时在 Linq-to-Entities 查询中,出现异常
System.NotSupportedException:方法“First”只能用作最终查询操作。请考虑在此实例中使用“FirstOrDefault”方法。

a) 我不明白为什么 First只能用作最终查询操作,因为在我们的示例中是 First被调用 IEnumerable<> ( ids1.First() ) 而不是 IQueryable<> .换句话说, First在 Linq-to-Objects 查询中调用,而不是在 Linq-to-Entities 查询中调用?!

b) 无论如何,为什么必须 First用作最终查询操作,而 FirstOrDefault不一定是最终查询操作?

谢谢

回复:

As for the difference between First() and FirstOrDefault() - I don't know. Have you tried it, and does it work?



是的,它有效

No, First() is being called in the LINQ to Entities query. Your where clause will be converted to: Where(c => c.EmployeeID == ids1.First())



a) 我现在有点困惑。我意识到 ids1.First本质上是在 Linq-to-Entities 查询中调用的,但事实仍然是 First被调用 IEnumerable<> ,因此 First在 Linq-to-Objects 查询中调用,而这个 Linq-to-Object 查询又在 Linq-To-entities 查询中调用——至少我是这么理解的?!

或者你是在暗示 First以某种方式调用 IQeryable<> ?

b) 我意识到 (c => c.EmployeeID == ids1.First())将被转换为表达式树,但为什么不 ids1.First()在转换发生之前执行?

c) 无论如何,一旦转换为表达式树,我假设当 sql 提供程序收到我们的 where 的表达式树时子句并尝试将其转换为 Sql 命令,此 Sql 提供程序没有“权力”来执行 ids1.First为了取回结果(然后将其放入 Sql 查询中),因此异常?!

第二次回复:

a) 我仍然很困惑为什么 ids1.First在转换为表达式树之前不执行?!即,带有以下子句
Where(c => c.EmployeeID == 2+3) 

表达式 2+3在此 Where 子句转换为表达式树之前执行!和 ids.First也是一种表达,所以我会期待类似的行为?!

b)抱歉重复了,但我的假设是否真的让我很烦 First在 Linq-to-Objects 查询中调用,而这个 Linq-to-Object 查询又在 Linq-To-entities 查询中调用——对吗?!

c) 也许我误解了您的帖子,但您是否暗示可以在 IEnumerable<> E 上调用大多数其他 Linq-to-Object 运算符, 即使 E包含在 Linq-to-Entities 查询中?

最佳答案

不,First()在 LINQ to Entities 查询中被调用。您的 where子句将转换为:

Where(c => c.EmployeeID == ids1.First())

该 lambda 表达式将被转换为表达式树。

当然,在查询之外执行此操作非常简单:
int firstId = ids1.First();
var employees = from c in context.Employees
where c.EmployeeID == firstId
select c;

这变得更简单:
int firstId = ids1.First();
var employees = context.Employees.Where(c => c.EmployeeID == firstId);

至于 First()的区别和 FirstOrDefault() - 我不知道。你试过了吗,它有效吗?也许是因为 First()在空序列上调用时会抛出异常,并且由于某种原因,该行为可能难以翻译。

编辑:是的,查询提供者可能会查看表达式树的那一点并解决它 - 但迟早你必须划清查询提供者的智能程度。它已经做了很多工作,而且你很容易在这里完成工作(根据我上面的例子) - 那么为什么不这样做呢?

请记住,从逻辑上讲, First()context.Employees 的每个元素执行- 因此,如果存在任何行,它只需要在空集合上抛出异常 - 否则 First()电话从不合乎逻辑地进行。看,它并不像你想象的那么简单 :) 在这种情况下,你碰巧知道有元素,所以你可以调用 First()事先不受惩罚 - 但查询提供者不能。

编辑:回复第二次编辑...

a) 表达式 2+3 是编译时常量。改为 x + 2加法运算将成为表达式树的一部分。特别是,如果您更改 x 的值, (或 ids1 在您的示例中)这将更改查询 - 您无法更改 2+3 的含义。

b)我不清楚你的意思是什么。 EF 查询中包含的表达式树包括对 Enumerable.First 的调用。 ,如果这就是你的意思。

c) 由查询提供者决定究竟支持哪些表达式树 - 这适用于其他方法调用(例如 int.Parse )以及 LINQ to Objects 方法。

关于linq-to-entities - 为什么EF throw "NotSupportedException: The method ' First'只能作为最终查询操作”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7811544/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com