How to filter IEnumerable based on entity input parameter

I am using the Entity framework now, but this is a problem "split" between all ORMs and even IEnumerable.

Say I have a method in MVC that looks like this:

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

I want to request a context based on an input parameter, for example:

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

But this is more complicated, because if one of the above parameters ( Date \ Name \ ItemCode ) is null, I do not want to include it in the request.
If I have hard code, it might look something like this:

 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); ... 

There should be an easier way than this. I need a way to generate an expression like Expression<T, bool> , which will be used in the Where method.

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

Is there a built-in way to create this expression? Is there a package in nuget that does this?


Update: There can be more than 30 posts in an entity model; record 30 times Where for each request there may be a pain in the neck:

 .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(); 
+6
source share
3 answers

Give it a try. It uses expressions and expressions to dynamically build a query. I tested it only with objects.

 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; } 
+5
source

Your hard coded method is the best method overall.

However, you can try to make your life a little easier by writing an appropriate extension method to help keep your code clean.

Try this for example:

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

Now you can write this code:

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

(Please remember to remove your context or use using to do this for you.)

+5
source

I think you should encapsulate your logic in your Foo entity, for example.

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

and use it in linq. Or look at the specification template.

+1
source

Source: https://habr.com/ru/post/925301/


All Articles