6

我现在正在使用实体框架-但这是所有 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)为空,我不想将它包含在查询中。
如果我硬编码,它看起来类似于:

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 多个属性;为每个查询写 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();
4

3 回答 3

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 回答
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 回答
1

我认为你应该将你的逻辑封装到你的 Foo 实体中,例如

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

并在 linq 中使用它。或查看规范模式

于 2012-09-13T10:52:50.280 回答