如何根据实体输入参数过滤IEnumerable

我正在使用现在的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); ... 

必须有一个比这更简单的方法。
我需要一种方法来生成要在Where方法中使用的Expression类型的Expression

 [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(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(); 

试试吧。 这是使用reflection和表达式动态构建查询。 我只用物体测试过它。

 static IQueryable Filter(IQueryable 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>(body, param); col = col.Where(lambda); } } return col; } 

您的硬编码方法通常是最好的方法。

但是,您可以尝试通过编写适当的扩展方法来帮助保持代码清洁,从而使您的生活更轻松。

试试这个例子:

 public static class QueryableEx { public static IQueryable Where( this IQueryable @this, bool condition, Expression> @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); } } 

(请不要忘记处理您的上下文或使用它来为您完成。)

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

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

并在linq中使用它。 或者看看规格模式