2012-09-13 19 views
6

私は今Entityフレームワークを使用していますが、すべてのORMとIEnumerable間で「共有」の問題です。エンティティ入力パラメータに基づいてIEnumerableをフィルタリングする方法

のは、私はMVCのメソッドを持っているとしましょうが、次のようになります。

[HttpPost] 
public ActionResult Foo(FooModel model) 
{ 
    var context = new Context(); -- The EF session 
    var data = context.Foo.Where(???).ToList(); 
    return View(data); 
} 

私は次のように入力パラメータに基づいてコンテキストを照会する:

var data = context.Foo.Where(x => x.Date == model.Date && 
          x.Name == model.Name && 
          x.ItemCode = model.ItemCode).ToList(); 

しかし、それはそれよりも複雑ですが、上記のパラメータ(Date \ Name \ ItemCode)のいずれかがnullの場合、クエリ内には含めたくないためです。
ことができます私はハードコードする場合は、次のようになります。

var query = context.Foo; 

if (model.Date != null) 
    query =query.Where(x => x.Date == model.Date); 

if (model.ItemCode != null) 
    query =query.Where(x => x.ItemCode == model.ItemCode); 
... 

これより簡単な方法があるに違いありません。
Whereメソッドで使用するタイプExpression<T, bool>の式を生成する方法が必要です。

[HttpPost] 
public ActionResult Foo(FooModel model) 
{ 
    var context = new Context(); -- The EF session 
    var data = context.Foo.Where(THE_EXPRESSION).ToList(); 
    return View(data); 
} 

この式をビルドする方法はありますか?それをするナゲットのパッケージはありますか?


更新:モデル・エンティティに30以上のproperitesがあるかもしれません。 30回書く各クエリの場所は首に痛みがあります。

.Where(model.Date != null, x => x.Date == model.Date) 
.Where(model.Name != null, x => x.Name == model.Name) 
.Where(model.ItemCode != null, x => x.ItemCode == model.ItemCode) 
... 
... 
... 
.ToList(); 

答えて

5

それを試してみてください。これは、リフレクションと式を使用してクエリを動的に構築しています。私はオブジェクトでのみテストしました。

static IQueryable<T> Filter<T>(IQueryable<T> col, T filter) 
{ 
    foreach (var pi in typeof(T).GetProperties()) 
    { 
     if (pi.GetValue(filter) != null) 
     { 
      var param = Expression.Parameter(typeof(T), "t"); 
      var body = Expression.Equal(
       Expression.PropertyOrField(param, pi.Name), 
       Expression.PropertyOrField(Expression.Constant(filter), pi.Name)); 
      var lambda = Expression.Lambda<Func<T, bool>>(body, param); 
      col = col.Where(lambda); 
     } 
    } 

    return col; 
} 
+0

このメソッドの使い方を示す例は非常に役に立ちます。 – devinbost

5

ハードコーディングされた方法が一般的に最良の方法です。

ただし、コードをきれいに保つのに役立つ適切な拡張方法を書いて、少しでも簡単にできるようにすることができます。

例えば、これを試してみてください:

public static class QueryableEx 
{ 
    public static IQueryable<T> Where<T>(
     this IQueryable<T> @this, 
     bool condition, 
     Expression<Func<T, bool>> @where) 
    { 
     return condition ? @this.Where(@where) : @this; 
    } 
} 

今、あなたは、このコードを書くことができます。

[HttpPost] 
public ActionResult Foo(FooModel model) 
{ 
    using (var context = new Context()) 
    { 
     var data = context.Foo 
      .Where(model.Date != null, x => x.Date == model.Date) 
      .Where(model.Name != null, x => x.Name == model.Name) 
      .Where(model.ItemCode != null, x => x.ItemCode == model.ItemCode) 
      .ToList(); 
     return View(data); 
    } 
} 

(あなたのコンテキストを処分またはあなたのためにそれを行うにはusingを使用することを忘れないでください。 )

+0

+1これは私の投票を得る - ユーザーがNで大きなテーブルを検索できる画面異なる順列はdbレベルでインデックスを作成することを悪夢にしています。各フィルタを開発者に見えるようにすることで、結果のクエリに対する可視性の少なくとも一部が得られ、どのフィールド(またはその組み合わせ)がユーザーに公開されるかを再考する可能性があります。 – StuartLC

+0

ご意見ありがとうございます。しかし、もし私のモデル実体が** 30以上**の定格を持っていれば30回書く。どこで(...)痛みを伴うことができる。 – gdoron

+0

@gdoron - はい、どこかに書き込む必要があります。あなたがリフレクションとビルディングの表現でこれをしようとすると、私は今あなたに2つの問題があると恐れています。 – Enigmativity

1

あなたのロジックをFooエンティティにカプセル化する必要があると思います。

public Foo 
    { 
    public bool isMatch(Model model) 
    { 
     // check your rules and return result 
    } 
    } 

linqで使用してください。または見てくださいSpecification pattern

+1

これはLINQ to Objectsのみで動作し、Entity Frameworkでは動作しません。 –

+0

公開式を返すことができます。> IsSatisfiedBy() – syned

+0

エンティティを完全に脅かすものです。 –

関連する問題