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

Aus*_*tin 5 c# linq sql-server asp.net-mvc entity-framework

我正在尝试使用Entity Framework整合访问不同表的逻辑.我创建了一个扩展方法,用于从我的注册实体中提取所有注册人:

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);
}
Run Code Online (Sandbox Code Playgroud)

这适用于这样的查询:

var attendees = db.Registrations.Attending().ToList();
Run Code Online (Sandbox Code Playgroud)

但是在子查询中使用它时不起作用:

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();
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

LINQ to Entities无法识别方法'System.Collections.Generic.IEnumerable 1[Registration] Attending(System.Collections.Generic.IEnumerable1 [Registration])'方法,并且此方法无法转换为商店表达式.

有没有办法在子查询中重用该代码?

Ger*_*old 8

你想要实现的主要是重用定义其含义的谓词Attending.您可以通过将表达式存储在一个只读变量中来实现,该变量可供应用程序中需要它的任何人使用,例如在静态类中ExpressionConstants.

public static readonly Expression<Func<Registration, bool>> IsAttending = 
    r => r.Status == RegistrationStatus.Paid
      || r.Status == RegistrationStatus.Assigned
      || r.Status == RegistrationStatus.Completed;
Run Code Online (Sandbox Code Playgroud)

那你可以做

var attendees = db.Registrations.Where(ExpressionConstants.IsAttending).ToList();
Run Code Online (Sandbox Code Playgroud)

并在子查询中使用:

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(),
})
Run Code Online (Sandbox Code Playgroud)

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