web-dev-qa-db-ja.com

LINQクエリを動的に生成する

オブジェクトがあります

public class SomeObject
{
   public Name {get;set;}
   public City {get;set;}
   public State {get;set}
   //various other parameters.  Let's say there's ~20
}

ソースコードを再コンパイルせずに、新しいLINQクエリを動的に作成することは可能ですか?代わりに、クエリパラメータは、データベースに格納および更新されるXML構造から取得されます。

var result = from i in someObj
             where 
             //XML requests Name = 'Bob'...so append this where clause
             name = 'Bob'

これはできますか?

34
P.Brian.Mackey

式ツリーを使用したソリューションは次のとおりです。

var param = Expression.Parameter(typeof(SomeObject), "p");
var exp = Expression.Lambda<Func<SomeObject, bool>>(
    Expression.Equal(
        Expression.Property(param, "Name"),
        Expression.Constant("Bob")
    ),
    param
);
var query = someObj.Where(exp);

私はそれがはるかに複雑であることを知っていますが、これは時には役立つかもしれません。

117
Balazs Tihanyi

Dynamic Linq を見てください。これにより、クエリ条件をテキストとして定義できます。

条件を動的に追加する場合、同様の構文を使用して条件をクエリに追加できます。

if(CategoryIsImportant)
    myQuery = myQuery.Where("CategoryId=2");

これらはすべて、選択したXML形式に(かなり簡単に)エンコードできます。

27

あなたの質問に基づいて伝えるのは難しいですが、場合によっては動的なLinqを必要とせず、単にこれを行うことができます...

var result = from o in someObj 
             where (Name == null || o.Name == Name)
             && (City == null || o.City == City)
             && (State == null || o.State == State)
             select o;

これにより、問題のパラメーターがnullの場合に、データがフィルターされなくなります。そして、C#の短絡動作のおかげで、まだうまく機能しています。

26
Steve Wortham

Expression Trees を実際に掘り下げる必要があると思います。あまり掘り下げていないので、サンプルを作成することはできませんが、Expression Treeを使用してクエリを動的に構築し、.Compile(コード内)を呼び出して実行できることを知っています。

実際、こちらがより良いリンクです 式ツリーを使用した動的クエリの構築 。それはあなたが望むものを正確に与えるべきであり、それが何であるかについてかなり簡潔です。これはあなたのための良い例として機能するはずです:)

9
Justin Pihony

多分Dynamic Linqがあなたを助けることができます: Dynamic linqパート1:linq動的クエリライブラリの使用

query = query.Where("Id = 123 And Age > 18");

または、Linqクエリを直接操作できます。

query = query.Where(x=>x.Id == 5);
8
Antineutrino

XMLのコンテンツに応じて、オプションのフィルターを導入することを想定しています。 StriplingWarriorの例を続けるには:

var name = GetNameFromXml();
var city = GetCityFromXml();
var state = GetStateFromXml();

var result = someObj;
if (name != null)
    result = result.Where(i => i.Name == name);
if (city != null)
    result = result.Where(i => i.City == city);
if (state != null)
    result = result.Where(i => i.State == state);

この方法では、XMLで実際に指定されている内容に応じて、任意の数のフィルター(なしから3つすべてまで)を適用します。

5
Douglas

はい、実際には非常に簡単です。

var name = GetBobNameFromXml();
var result = someObj.Where(i => i.Name == name);

基準を少しずつ適用するかどうかも選択できます。

var result = someObj;
var name = xmlCriteria.Name;
if(!string.IsNullOrEmpty(name))
{
    result = result.Where(i => i.Name == name);
}
// follow the same pattern for city, state, etc.

ifステートメントの束を回避するために、基準関数の名前キー付き辞書を使用するパターンを使用することもできます。

foreach(var criterionPair in xmlCriteria)
{
    var value = criterionPair.Value;
    result = result.Where(i => propGetters[criterionPair.PropertyName](i, value));
}

基本的に、これらの線に沿ってできることはたくさんあります。より具体的に自分の状況に合わせた回答が必要な場合は、より具体的な質問を提供する必要があります。

3