6

私は現在EntityFrameworkを使用していますが、すべてのORM間、さらには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ただし、上記のパラメータの1つ( \ 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);
}

その式を構築するための組み込みの方法はありますか?それを行うnugetのパッケージはありますか?


更新:モデルエンティティには30を超えるプロパティが存在する可能性があります。各クエリのWhereを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();
4

3 に答える 3

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;
}
于 2012-09-13T11:25:00.247 に答える
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ください。)

于 2012-09-13T10:45:25.430 に答える
1

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

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

そしてそれをlinqで使用します。または、仕様パターンを参照してください

于 2012-09-13T10:52:50.280 に答える