7

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 をサポートしていないというエラーが表示されます。このようなデリゲートの代わりにインライン コードを使用できないのはなぜですか? 他の方法で再利用を実現する方法はありますか?

4

3 に答える 3

6

内部では、生成した を SqlLinq-to-{DATABASE}に変換しているだけであることを思い出してください。IQueryable

そのようなコードをインライン化することはできません。なぜなら、 (またはInvokeを呼び出したときに実際に呼び出しているメソッド) には、それを SQL ステートメントに変換する一貫した方法がないからです (そこで何かを行うことができます)。FuncAction

つまり、パーツを分割して再利用できます。

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

問題は、IQueryableRDBMSに渡すSQL式を生成する必要があり、それが不透明な述語しかない場合はそれを実行できないことです。

明らかですが非効率的な方法は、クエリを次のように書き直すことです。

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 に答える