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