I've a list of expressions:
List<Expression<Func<Domain.FollowUpActivity, bool>>> fuaExpressions = null;
I need to join all of them on a single OR expression:
I've tried this:
Expression body = Expression.Constant(false);
foreach (var orExpression in orExpressions)
foreach (Expression orExp in orExpression.Expressions)
body = Expression.Or(body, orExp);
It throws me an InvalidOperationException due to boolean operator is not defined between Expression<Boolean> and Expression<Func<T, bool>>
Some help please?
From a great book by Albahari brothers:
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T> () { return f => true; }
public static Expression<Func<T, bool>> False<T> () { return f => false; }
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.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
}
}
Use it like this:
List<Expression<Func<Domain.FollowUpActivity, bool>>> fuaExpressions = null;
Expression<Func<Domain.FollowUpActivity, bool>> result = PredicateBuilder.False<Domain.FollowUpActivity>();
foreach (var exp in fuaExpressions)
{
result = PredicateBuilder.Or(result, exp);
}
Related
public static Expression<Func<T, bool>> OrElse<T>(this
Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
ParameterExpression parameter = Expression.Parameter(typeof(T));
ReplaceExpressionVisitor leftVisitor =
new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
Expression left = leftVisitor.Visit(expr1.Body);
ReplaceExpressionVisitor rightVisitor =
new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
Expression right = rightVisitor.Visit(expr2.Body);
return Expression.Lambda<Func<T, bool>>(Expression.OrElse(left, right), parameter);
}
Since I have another method where the only difference is the expression in the return statement, how to pass Expression.OrElse as a parameter to the method (my other method uses AndAlso)?
Since the methods are close to identical I would like one common method with the expression passed as a parameter.
I've tried passing a BinaryExpression without success.
What about that?
public static Expression<Func<T, bool>> BinaryOp<T>(this
Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2,
Func<Expression, Expression, BinaryExpression> operation)
{
ParameterExpression parameter = Expression.Parameter(typeof(T));
ReplaceExpressionVisitor leftVisitor =
new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
Expression left = leftVisitor.Visit(expr1.Body);
ReplaceExpressionVisitor rightVisitor =
new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
Expression right = rightVisitor.Visit(expr2.Body);
return Expression.Lambda<Func<T, bool>>(operation(left, right), parameter);
}
public static Expression<Func<T, bool>> OrElse<T>(this
Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
return BinaryOp(expr1, expr2, Expression.OrElse); // passed as mth group
}
public static Expression<Func<T, bool>> AndAlso<T>(this
Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
return BinaryOp(expr1, expr2, Expression.AndAlso); // passed as mth group
}
I'm using C# 2010 .NET 4.0 and I have a List<T> collection called returns that I need to build a dynamic LINQ query on.
I'm utilizing the Predicate Builder referenced here.
This works fine if I have 1 filter criteria, but if I have 2 or more, then, when the query.compile() is called, I get this error:
variable 'tmp' of type 'Check21Tools.IncomingReturn' referenced from
scope '', but it is not defined
Code:
Expression<Func<Check21Tools.IncomingReturn, bool>> query = null;
bool hasFilterItems = false;
if (filterArray != null)
{
foreach (string s in filterArray)
{
if (s == string.Empty)
{ break; }
else
{
hasFilterItems = true;
Int64 id = Int64.Parse(s);
query = query.Or(tmp => tmp.ID == id);
}
}
}
if (hasFilterItems)
{
returns = returns.Where(query.Compile()).CreateFromEnumerable
<Check21Tools.IncomingReturns, Check21Tools.IncomingReturn>();
}
Code:
public static Expression<Func<T, bool>> Or<T>(
this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
if (expr1 == null) return expr2;
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, expr2.Body), expr1.Parameters);
}
[The OP has] stumbled across an updated version of the predicate builder that works on List<T> objects:
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
{
if (expr1 == null) return expr2;
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}
in MongoDb I can pass a predicate to an queryable instance for example
DataBase.GetCollection<BsonDocument>("entity")
.AsQueryable<Entity>()
.Where(item=>item.id ==5);
But now I have function like this
IEnumerbale QueryData(Predicate<Entity> condition)
{
this.DataBase.GetCollection<BsonDocument>("entity")
.AsQueryable<Entity>()
.Where(item=> condition(item));
}
but this does not work and tells me:
Unsupported where clause: .
Is this as designed?
is there any workaround ? Am I doing something wrong?
You're not even passing an expression. Your condition is a totally opaque function to MongoDB.
You need to pass in an Expression<Func<Entity,bool>> and call Where like this:
Where(condition)
The Where clause must be translated to a MongoDB query that is sent to the server. When you pass in an arbitrary Predicate like that the LINQ layer has no idea what to translate it to. So that type of open-ended Where clause can't be supported.
Pass Lambda expression as parameter to filter data from mongodb collection.
Your data filter function could be
public IEnumerable<BsonDocument> FindAllWithPredicate(Func<BsonDocument, bool> condition)
{
return Collection.AsQueryable().Where(condition).ToArray();
}
Predicatebuilder.cs
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T>()
{
return f => true;
}
public static Expression<Func<T, bool>> False<T>()
{
return f => false;
}
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.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
}
}
Generate lambda expression by predicate builder
public static class PredicateBuilderStore
{
public static Func<BsonDocument, bool> GetPredicateForBsonDocument(Entity entity)
{
var predicate = PredicateBuilder.True<BsonDocument>();
predicate = predicate.And(d => d.GetElement({key}).Value == CompareWithValue);
return predicate.Compile();
}
}
if you want to query just all items, you could do it as:
return this.collection.Find(_=>true).ToArray();
I have an application and I'm trying to implement DDD concepts. I have my repository class with some method to list entities. I would like to know how can I do a query with QueryOver to filter separating with AND operator, when the parameter is filled, sample
public IEnumerable<Product> FindProducts(string name, decimal? price, DateTime? validDate, int? stock, int? idSupplier)
{
var query = Session.QueryOver<Product>().OrderBy(x => x.Name).Asc;
if (!string.IsNullOrEmpty(name))
// add where condition for name parameter
if (price.HasValue)
// add 'AND' where condition for price parameter
if (validDate.HasValue)
// add 'AND' where condition for validDate parameter
if (idSupplier.HasValue)
// add 'AND' where condition for idSupplier parameter
// other possible conditions
return query.List();
}
Is there any way to do that before I use HQL string query? hehehe
Thank you!
Here, use PredicateBuilder:
How To:
IQueryable<Product> SearchProducts (params string[] keywords)
{
var predicate = PredicateBuilder.False<Product>();
foreach (string keyword in keywords)
{
string temp = keyword;
predicate = predicate.Or (p => p.Description.Contains (temp));
}
return dataContext.Products.Where (predicate);
}
PredicateBuilder Source:
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
public static class PredicateBuilder
{
public static Expression<Func<T, bool>> True<T> () { return f => true; }
public static Expression<Func<T, bool>> False<T> () { return f => false; }
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.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
}
}
For more information on PredicateBuilder and LinqKit go here: http://www.albahari.com/nutshell/linqkit.aspx
I have an array of
Expression<Func<MyClass,bool>>
However, I want to AND them all together to get just a single item of that type. How do I do this? Can I cast the result of Expression.And?
If you use the following extension method:
public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
}
From here: http://www.albahari.com/nutshell/predicatebuilder.aspx
Then you can just write this to fold them all down to one expression.
public Expression<Func<T, bool>> AggregateAnd(Expression<Func<T,bool>>[] input)
{
return input.Aggregate((l,r) => l.And(r));
}