use*_*769 7 linq-to-objects linq-to-entities
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
Run Code Online (Sandbox Code Playgroud)
当尝试ids1.First在Linq-to-Entities查询中调用时,我得到一个异常
System.NotSupportedException:方法'First'只能用作最终查询操作.请考虑在此实例中使用方法"FirstOrDefault".
a)我不明白为什么First只能用作最终查询操作,因为在我们的例子First中调用on IEnumerable<>(ids1.First())而不是on IQueryable<>.换句话说,First在Linq-to-Objects查询中调用而不是在Linq-to-Entities查询中调用?!
b)无论如何,为什么必须First用作最终查询操作,而FirstOrDefault不必进行最终查询操作?
谢谢
答复:
至于First()和FirstOrDefault()之间的区别 - 我不知道.你试过了吗,它有效吗?
是的有效
不,在LINQ to Entities查询中调用First().您的where子句将转换为:Where(c => c.EmployeeID == ids1.First())
a)我现在有点困惑.我意识到ids1.First在Linq-to-Entities查询中基本上被调用,但事实仍然是First被调用IEnumerable<>,因此First在Linq-to-Objects查询中被调用,而这个Linq-to-Object查询又在Linq-中调用到实体查询 - 至少这是我理解的方式?!
或者你是暗示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)
Run Code Online (Sandbox Code Playgroud)
表达式2+3在此Where子句转换为表达式树之前执行!并且ids.First也是一种表达,所以我期望类似的行为?!
b)很抱歉重复,但是我的假设 -
First在Linq-to-Objects查询中调用,而Linq-to-Object查询又在Linq-To-entities查询中调用 - 是否正确? !
c)也许我误解了你的帖子,但你是否暗示大多数其他Linq-to-Object操作符都可以被调用IEnumerable<> E,即使E它包含在Linq-to-Entities查询中?
不,First() 是被称为在LINQ到实体查询.您的where条款将转换为:
Where(c => c.EmployeeID == ids1.First())
Run Code Online (Sandbox Code Playgroud)
该lambda表达式将转换为表达式树.
当然,在查询之外执行此操作非常简单:
int firstId = ids1.First();
var employees = from c in context.Employees
where c.EmployeeID == firstId
select c;
Run Code Online (Sandbox Code Playgroud)
这变得更简单:
int firstId = ids1.First();
var employees = context.Employees.Where(c => c.EmployeeID == firstId);
Run Code Online (Sandbox Code Playgroud)
至于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方法.