Linq query with dynamic predicates at where clause connected to OR

you can easily create dynamic queries in C # if you add more restrictions to the current query.

var list = new List<Item>(); var q = list.AsQueryable(); q = q.Where(x => x.Size == 3); q = q.Where(x => x.Color == "blue"); 

In this case, each new predicate is added that performs the AND operation with the previous one. The previous result is equivalent to:

 q = list.Where(x => x.Size == 3 && x.Color == "blue"); 

Is it possible to achieve the same result, but with OR instead of AND?

 q = list.Where(x => x.Size == 3 || x.Color == "blue"); 

The idea is to have a variable number of expressions that are connected to the OR operator.

The expected result should be written in a sense as similar to the following pseudo-code:

 var conditions = new List<Func<Item, bool>>(); 

And later iteration conditions for creating something like:

 foreach(var condition in conditions) finalExpression += finalExpression || condition; 
+4
source share
2 answers

Thanks to Rafael Altaus, who gave the following link:

http://www.albahari.com/nutshell/predicatebuilder.aspx

The predicate constructor is the solution. You can use it to install LinqKit from Nuget. In this url you can also find an implementation of this class.

Note: to do this work with LinqToSql or LinqToEntities, IQueriable Object must be converted using the "AsExpandable ()" method, it is not required for memory objects

+1
source

Another possible solution to this, especially when someone does not want to use an external library, is to use expression trees.

Add the following expression extension:

 public static Expression<Func<T, bool>> Or<T>( this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2) { var invokedExpr = Expression.Invoke(expr2, expr1.Parameters); return Expression.Lambda<Func<T, bool>>( Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters); } 

As an example, suppose you have a Container object that has a nested InnerContainer object with two Name and Id properties. Then you can use it as follows:

 Expression<Func<Container, bool>> whereQuery = c => c.InnerContainer.Name == "Name1"; whereQuery = whereQuery.Or(c => c.InnerContainer.Name == "Name2"); whereQuery = whereQuery.Or(c => c.InnerContainer.Id == 0); var result = query .Where(whereQuery) .ToList(); 

Materializing such a query will result in the following SQL:

 SELECT [x].[Id], [x].[InnerContainerId] FROM [Containers] AS [x] LEFT JOIN [InnerContainer] AS [x.InnerContainer] ON [x].[InnerContainerId] = [x.InnerContainer].[Id] WHERE [x.InnerContainer].[Name] IN (N'Name1', N'Name2') OR ([x].[InnerContainerId] = 0) 

This way you can keep lambdas in the collection and scroll through them.

0
source

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


All Articles