【发布时间】:2017-01-30 03:08:47
【问题描述】:
有人可以向我解释为什么 EF 引擎在以下情况下会失败吗?
它适用于以下表达式:
var data = context.Programs
.Select(d => new MyDataDto
{
ProgramId = d.ProgramId,
ProgramName = d.ProgramName,
ClientId = d.ClientId,
Protocols = d.Protocols.Where(p => p.UserProtocols.Any(u => u.UserId == userId))
.Count(pr => pr.Programs.Any(pg => pg.ProgramId == d.ProgramId))
})
.ToList();
但是如果我将一些封装成扩展方法:
public static IQueryable<Protocol> ForUser(this IQueryable<Protocol> protocols, int userId)
{
return protocols.Where(p => p.UserProtocols.Any(u => u.UserId == userId));
}
结果查询:
var data = context.Programs
.Select(d => new MyDataDto
{
ProgramId = d.ProgramId,
ProgramName = d.ProgramName,
ClientId = d.ClientId,
Protocols = d.Protocols.ForUser(userId)
.Count(pr => pr.Programs.Any(pg => pg.ProgramId == d.ProgramId))
})
.ToList();
失败并出现异常:LINQ to Entities 无法识别方法 'System.Linq.IQueryable1[DAL.Protocol] ForUser(System.Linq.IQueryable1[DAL.Protocol], Int32)' 方法,并且此方法不能翻译成商店表达式。
我希望 EF 引擎构建整个表达式树,链接必要的表达式,然后生成 SQL。为什么不这样做?
【问题讨论】:
-
见 stackoverflow.com/a/36736907/1625737 和 stackoverflow.com/a/29960775/1625737,但不确定它是否适用于扩展方法
-
感谢您的提示。我已经开始寻找这条路,但我需要一段时间来消化所有关于表达式和函数的内容。同时,有没有办法像 Expression
> (这里的 T 可能是协议)重写我的扩展方法,以便它可以满足我的预期用途? -
我不确定 LinqKit 能否在这里提供帮助。我认为@StriplingWarrior 的回答是最明智的做法。
-
d.Protocols似乎是一个导航属性,因此不可能是IQueryable<Protocol>(很可能是ICollection<Protocol>),对吧? -
EF6 是否支持编译查询(或等效查询)? LINQ to SQL 和旧版本的 EF 将允许您创建这样的方法。否则,您也许可以使用linqkit。
标签: c# entity-framework linq entity-framework-6 extension-methods