LINQ to Entities不支持扩展方法?

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)'方法,并且此方法无法转换为商店表达式.

现在我有两个问题:

  1. 我搜索了这个错误,发现许多问题与我在stackoverflow中的问题相同.所有答案都是"Linq to Entities无法将此扩展方法转换为SQL查询".如果有人帮助我知道,为什么我的第一个查询没有引起任何错误,我将不胜感激?

  2. 如何更改Linq-to-Entities可以识别的扩展方法?

mr1*_*100 8

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)