LINQ to Entities不支持扩展方法?

10

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

  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.IQueryable1[..](System.Linq.IQueryable1[..., System.DateTime)'方法,这个方法无法被转换成存储表达式。

现在我有两个问题:

  1. 我在谷歌上搜索了这个错误,并在stackoverflow上找到了很多与我的问题相同的答案。所有答案都是“Linq to Entities不能将此扩展方法转换为SQL查询”。现在,如果有人能帮我知道,为什么我的第一个查询没有引发任何错误,我将非常感激。

  2. 如何更改我的扩展方法以便Linq-to-Entities能够识别它?

1个回答

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参数中,您不能调用任何方法,必须提供适当的Expression。 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));
}

我认为你的扩展方法和我的扩展方法没有什么不同,因为 queryable.Where(ExpressionsHelper.CurrentVersion(date)) 等同于 queryable.Where(p => p.CreationDate>date); - M.Azad
但是我的CurrentVersion扩展方法版本无法应用于您的嵌套查询!您只能在像Db.Groups.CurrentVersion()这样的简单查询中使用它!对于复杂的查询,您需要使用Db.Groups.SelectMany(p => p.GroupMembers.AsQueryable().Where(ExpressionsHelper.CurrentVersion(date)))。该扩展方法仅作为示例提供 - 如果您希望拥有它,则可以避免代码重复。 - mr100
不要纠结于扩展方法,它只会让你更困惑。在我看来,在嵌套查询中根本无法使用它。对于简单情况,它们是很有帮助的。 - mr100
你的意思是没有任何方法可以创建一个扩展方法来支持这个问题吗? - M.Azad
我认为使用扩展方法无法合理地实现您想要的功能,但是有一种方法可以通过静态方法共享部分逻辑(例如)来实现与您最初想要的类似的功能。 - mr100
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接