LINQ to Entities不支持扩展方法?

时间:2015-07-14 07:08:43

标签: c# linq entity-framework linq-to-entities

我有两个像这样的扩展方法

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

现在我有两个问题:

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

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

1 个答案:

答案 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));
}