LINQ to Entities不支持调用

时间:2012-05-16 15:39:13

标签: c# linq-to-entities

我在LINQ to Entities中有以下查询:

var query = from p in db.Products
            where p.Price > 10M
            select p;

此时查询尚未执行,我想编写一个根据某些条件返回true / false的查询:

return query.Any(p => p.IsInStock &&
               (p.Category == "Beverage" ||
               p.Category == "Other"));

这很好用;但是,我想从我的代码中重用一些东西。我有很多方法需要根据类别是饮料还是其他来过滤,所以我尝试创建一个委托:

Func<Product, bool> eligibleForDiscount = (product) => product.Category == "Beverage" || product.Category == "Other";

我想用委托代替内联检查:

return query.Any(p => p.IsInStock && eligibleForDiscount(p));

这给我一个错误,说LINQ to Entities不支持Invoke。为什么我不能将内联代码替换为这样的委托,有什么方法可以通过其他方式实现我的重用?

3 个答案:

答案 0 :(得分:6)

回想一下,引擎Linq-to-{DATABASE}只是将您生成的IQueryable转换为Sql。

您无法内联这样的代码,因为Invoke(您在调用FuncAction时实际调用的方法)没有一致的方法将其转换为一个sql语句(你可以在那里做任何)。

那说你可以通过拆分来重复使用部件:

var query = from p in db.Products
            where p.Price > 10M
            select p;

query = query.Where(p => p.IsInStock);
query = query.Where(p => p.Category == "Beverage" || p.Category == "Other");
return query.Any();

这些都可以放入采用IQueryable<Product>并返回相同(但已过滤)的方法中。然后你可以重复使用你的内容!

答案 1 :(得分:2)

问题是IQueryable需要生成一个SQL表达式来传递给RDBMS,当它只有一个不透明的谓词时它就不能这样做。

显而易见但效率低下的方法是按如下方式重写查询:

return query.Where(p => p.IsInStock).AsEnumerable().Any(eligibleForDiscount);

一种不那么简单的方法如下:

bool GotEligible(Expression<Func<Product,bool>> pred) {
    return query.Where(p => p.IsInStock).Any(pred);
}

请注意,此方法不是谓词,而是采用谓词表达式。现在它对EF是透明的,并且可以毫无问题地转换为SQL查询。

答案 2 :(得分:0)

只要您坚持使用IQueryable,就可以在函数中保留可重用的查询。

  public IQueryable<Product> EligibleForDiscount(IQueryable<Product> products)
  {
       return products.Where(p => product.Category == "Beverage" || 
                                  product.Category == "Other");
  }

现在像任何其他函数一样调用它:

  IQueryable<Product> query = (from p in db.Products
                               where p.Price > 10M
                               select p);

  query = EligibleForDiscount(query);