我可以在Entity Framework SubQuery中使用扩展方法吗?

问题描述:

我想巩固使用实体框架访问不同表的逻辑。我创建了从我的注册主体拉动所有登记在该人正在参加一个扩展方法:我可以在Entity Framework SubQuery中使用扩展方法吗?

public static IEnumerable<Registration> Attending(this IEnumerable<Registration> registrations) 
{ 
    return registrations.Where(r => r.Status == RegistrationStatus.Paid || r.Status == RegistrationStatus.Assigned || r.Status == RegistrationStatus.Completed); 
} 

这对于这样的疑问的伟大工程:

var attendees = db.Registrations.Attending().ToList(); 

但在使用时,它不工作子查询:

ProductTotals = db.Products.Where(p => p.EventID == ev.Id).Select(p => new ProductSummaryViewModel 
{ 
    ProductID = p.ProductID, 
    ProductName = p.Name, 
    Registrations = p.Registrations.Attending().Count(), 
}).ToList(); 

我得到以下错误:

LINQ to Entities does not recognize the method 'System.Collections.Generic.IEnumerable 1[Registration] Attending(System.Collections.Generic.IEnumerable 1[Registration])' method, and this method cannot be translated into a store expression.

是否有任何方式在子查询中重用该代码?

+0

您可以在'Select'之前使用'AsEnumerable()'在内存中执行操作。尽管您失去了在数据库级别执行它的优势。 – Shoe 2014-09-02 13:24:47

+2

如果您在EF查询中使用该方法,则该方法应该接受并返回'IQueryable'而不是'IEnumerable',否则查询不会在数据库上执行。 – Servy 2014-09-02 14:02:55

+0

@Servy谢谢,我注意到同样的事情,并改变了使用IQueryable – Austin 2014-09-02 17:35:41

您尝试实现的主要目标是重复使用定义Attending的含义的谓词。你可以通过将表达式存储在一个只读变量中来实现这一点,任何需要它的应用程序都可以使用该变量,例如在静态类ExpressionConstants中。

public static readonly Expression<Func<Registration, bool>> IsAttending = 
    r => r.Status == RegistrationStatus.Paid 
     || r.Status == RegistrationStatus.Assigned 
     || r.Status == RegistrationStatus.Completed; 

然后,你可以做

var attendees = db.Registrations.Where(ExpressionConstants.IsAttending).ToList(); 

而在子查询中使用:

ProductTotals = db.Products.Where(p => p.EventID == ev.Id).Select(p => new ProductSummaryViewModel 
{ 
    ProductID = p.ProductID, 
    ProductName = p.Name, 
    Registrations = p.Registrations.AsQueryable() // AsQueryable() 
        .Where(ExpressionConstants.IsAttending).Count(), 
}) 

AsQueryable()是必要的,因为p.Registrations可能是一个ICollection