为什么在编译为sql时EF 5.0不支持此EF 4.x LINQ语法? [英] Why does EF 5.0 not support this EF 4.x LINQ syntax when compiling to sql?

查看:70
本文介绍了为什么在编译为sql时EF 5.0不支持此EF 4.x LINQ语法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些代码最近从EF 4.2升级到EF 5.0(实际上是EF 4.4,因为我在.Net 4.0上运行).我发现我必须更改查询的语法,并且对原因感到好奇.让我从问题开始.

I have some code that was recently upgraded from EF 4.2 to EF 5.0 (actually EF 4.4 since I am running on .Net 4.0). I have discovered that I had to change the syntax of my query, and I'm curious as to why. Let me start off with the problem.

我有一个EventLog表,该表由客户端定期填充.对于每个事件日志,都会在报告"表中创建一个条目.这是一个定期运行的查询,用于发现报告"表中尚无条目的任何事件日志.我在EF 4.2中使用的查询是:

I have an EventLog table that is populated by the client periodically. For each event log an entry is created in a Report table. This is the query that is run periodically to discover any event logs that do not have an entry in the Report table yet. The query I used in EF 4.2 was:

from el in _repository.EventLogs
where !_repository.Reports.Any(p => p.EventLogID == el.EventlogID)

自从升级到EF 5.0之后,我在运行时收到以下错误:

Since upgrading to EF 5.0 I get the following error at runtime:

System.NotSupportedException:无法创建恒定值 键入"Namespace.Report".仅原始类型或枚举类型 在这种情况下受支持.

System.NotSupportedException: Unable to create a constant value of type 'Namespace.Report'. Only primitive types or enumeration types are supported in this context.

我发现用连接语法重写它可以解决此问题.以下内容在EF 5.0中有效,并且大致等效:

I discovered that rewriting it with the join syntax fixed the issue. The following works in EF 5.0 and is roughly the equivalent:

from eventLog in _repository.EventLogs
join report in _repository.Reports on eventLog.EventlogID equals report.EventLogID into alreadyReported
where !alreadyReported.Any()

对于第一个查询的混合语法/样式,有些人可能有不同的意见,但是我对此真的更感兴趣. EF 4.2编译器可以为原始查询生成SQL,但是EF 5.0拒绝,这似乎很奇怪.这是我所缺少的设置,还是两者之间的约束越来越严格?为什么会这样?

Some people may have mixed opinions about the mixed syntax/style of the first query, but I'm really more interested in the why of this. It seems odd that the EF 4.2 compiler could generate the SQL for the original query but that the EF 5.0 refuses. Is this a setting I am missing or just a tightening of constraints between the two? Why is this happening?

推荐答案

问题是由存储库返回的类型引起的;当_repository.Reports不是IQueryable<T>时,可以重现该问题.在那种情况下,Reports被认为是非标量变量.顺便说一下,这在LINQ中是不允许的.请参见引用不支持的非标量变量

The problem is caused by the type returned by your repository; the problem can be reproduced when _repository.Reports is not IQueryable<T>. In that case the Reports is considered as a non-scalar variable; which by the way is not allowed in LINQ. See Referencing Non-Scalar Variables Not Supported

关于第二个查询为何起作用的问题,基本上是IQueryable<T>的以下扩展方法,该组将其与IEnumerable<TInner>相连.

On your question regarding why the second query works, it is basically the following extension method of IQueryable<T> which group joins it with IEnumerable<TInner>.

public static IQueryable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(
    this IQueryable<TOuter> outer,IEnumerable<TInner> inner,
    Expression<Func<TOuter, TKey>> outerKeySelector,
    Expression<Func<TInner, TKey>> innerKeySelector,
    Expression<Func<TOuter, IEnumerable<TInner>, TResult>> resultSelector)

仅接受外部和内部键选择器的表达式(而不是引用非标量变量);其中上述限制不适用.

Which just accepts the expression for the key selectors for both outer and inner(instead of referencing non scalar variables); in which the above constraint doesn't apply.

注意:如果_repository.ReportsIQueryable<T>,则第一个查询将生效;否则,第一个查询将生效.因为EF会正确构建表达式树并执行适当的SQL.

Note: If _repository.Reports is of IQueryable<T> the first query will work; because EF will build the expression tree correctly and execute the appropriate SQL.

这篇关于为什么在编译为sql时EF 5.0不支持此EF 4.x LINQ语法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆