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
尝试在Linq-to-Entities查询中调用ids1.First
时,我收到异常
System.NotSupportedException:方法“First”只能用作最终查询操作。请考虑在此实例中使用方法“FirstOrDefault”而不是。
a)我不明白为什么First
只能用作最终查询操作,因为在我们的示例First
上调用IEnumerable<>
(ids1.First()
)而不是IQueryable<>
。换句话说,在Linq-to-Objects查询中调用First
而不是Linq-to-Entities查询?!
b)无论如何,为什么First
必须用作最终查询操作,而FirstOrDefault
不必是最终查询操作?
谢谢
REPLY:
至于First()和FirstOrDefault()之间的区别 - 我没有 知道。你试过了吗,它有效吗?
是的有效
不,在LINQ to Entities查询中调用First()。你的位置 子句将转换为:Where(c =&gt; c.EmployeeID == ids1.First())
a)我现在有点困惑。我意识到ids1.First
基本上是在Linq-to-Entities查询中调用的,但事实仍然是在First
上调用IEnumerable<>
,因此在Linq-中调用First
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
也是各种各样的表达,所以我期望类似的行为?!
First
,然后在Linq-To-entities查询中调用此Linq-to-Object查询 - 是否正确?!
c)也许我误解了你的帖子,但你暗示大多数其他Linq-to-Object运算符都可以在IEnumerable<> E
上调用,即使Linq-to-Entities查询中包含E
?
答案 0 :(得分:8)
不,在LINQ to Entities查询中调用First()
。您的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方法。