我有两个像这样的扩展方法
public static IQueryable<T> CurrentVersion(this IQueryable<T> queryable, DateTime date)
{
return queryable.Where(p => p.CreationDate>date);
}
public static IEnumerable<T> CurrentVersion(this IEnumerable<T> queryable, DateTime date)
{
return queryable.Where(p => p.CreationDate>date);
}
我的模特是
public class Group {
..
ICollection<GroupMembers> GroupMembers { get; set; }
}
当我在此查询中使用扩展方法时,一切正常
var q = Db.Groups.CurrentVersion();
var result = q.ToList();
但是当我在流动查询中使用它时会出现错误
var q = Db.Groups.SelectMany(p => p.GroupMembers.AsQueryable().CurrentVersion(date));
OR
var q = Db.Groups.SelectMany(p => p.GroupMembers.AsEnumerable().CurrentVersion(date));
var result = q.ToList(); // Here I get error
错误:
LINQ to Entities无法识别方法'System.Linq.IQueryable
1[..](System.Linq.IQueryable
1 [...,System.DateTime)'方法,并且此方法无法转换为商店表达式。
现在我有两个问题:
我搜索了这个错误,发现了许多与stackoverflow中的问题相同的问题。所有答案都是“Linq to Entities无法将此扩展方法转换为SQL查询”。如果有人帮助我知道,为什么我的第一个查询没有引起任何错误,我将不胜感激?
如何更改Linq-to-Entities可识别的扩展方法?
答案 0 :(得分:8)
Linq查询需要转换为sql。当您将CurrentVersion扩展名称为内联调用时:
Db.Groups.CurrentVersion();
然后EF只调用CurrentVersion方法,得到生成的IQueryable对象并转换为查询。另一方面,在该查询的情况下:
var q = Db.Groups.SelectMany(p => p.GroupMembers.AsQueryable().CurrentVersion(date));
SelectMany中的内部表达式可能永远不会在代码中调用!它意味着被翻译成sql。所以它被视为Expression对象然后被解析,但在你的情况下,它包含Invoke Expression,因为你正在调用方法但是这不能从明显的原因转换为sql。因此,从SelectMany lambda参数中你不能调用任何方法,你必须提供适当的表达式。 CurrentVersion方法提供的最有价值的东西是过滤表达式。像这样改变你的方法:
public static Expression<T, bool> CurrentVersion( DateTime date)
{
return p => p.CreationDate > date;
}
使用它是这样的:
var q = Db.Groups.Where(ExpressionsHelper.CurrentVersion(date));
...
Expression<T, bool> filterExpression = ExpressionsHelper.CurrentVersion(date);
Db.Groups.SelectMany(p => p.GroupMembers.AsQueryable().Where(filterExpression));
如果您愿意,您可以使用新方法分享过滤逻辑:
public static IQueryable<T> CurrentVersion(this IQueryable<T> queryable, DateTime date)
{
return queryable.Where(ExpressionsHelper.CurrentVersion(date));
}