我现在使用的是 Entity Framework -但这是所有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\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);
...

肯定有比这更简单的方法。
我需要一种生成类型Expression<T, bool>的表达式的方法,该表达式将在Where方法中使用。
[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多个属性。为每个查询编写30倍的Where可能会让人头疼:
.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();

最佳答案

试试看这是使用反射和表达式动态构建查询。我仅用对象对其进行了测试。

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;
}

10-02 03:15
查看更多