7

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

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

此时查询尚未执行,我想编写一个查询,该查询将根据某些条件返回真/假:

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。为什么我不能用内联代码代替这样的委托,有什么办法可以通过其他方式完成我的重用?

4

3 回答 3

6

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

您不能像这样内联代码,因为 an Invoke(您在调用Funcor时实际调用的方法Action)没有一致的方法将其转换为 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>并返回相同(但已过滤)的方法中。然后,您可以随心所欲地重复使用!

于 2012-05-16T15:48:12.647 回答
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 查询。

于 2012-05-16T15:52:42.253 回答
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);
于 2016-01-11T10:25:17.227 回答