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
}
Related
I want a function Expression> AnyColumnContains(string[] value)
that iterates through all Columns of a table and checks an array of values against the columns and returns true only if every value is contained in any column.
i already have a function that matches every column against one value but i have problems extending it to check the columns against every value
This is what i've got:
Expression<Func<T, bool>> AnyColumnContains<T>(string value){
var p = Expression.Parameter(typeof(T), "entity");
var fieldAccessors = typeof(T)
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(f => f.PropertyType == typeof(string))
.Select(f => Expression.Property(p, f))
.ToArray();
var fieldArray = Expression.NewArrayInit(typeof(string), fieldAccessors);
var concatCall = Expression.Call(typeof(string).GetMethod(
"Concat", new[] { typeof(string[]) }), fieldArray);
var contains = Expression.Call(
concatCall,
typeof(string).GetMethod("Contains", new[] { typeof(string) }),
Expression.Constant(value));
return Expression.Lambda<Func<T, bool>>(contains, p);
}
I tried to use a own extension method and replaced Contains with it but the problem is that i use sqlite and the expression cannot be converted since the Provider doesn't know the methods
This is what i want:
Expression<Func<T, bool>> AnyColumnContains<T>(string[] values){
// ... //
var contains = // build Expression Tree that matches all values against concatCall and only returns true if all values are contained.
return Expression.Lambda<Func<T, bool>>(contains, p);
}
Rather than making an entirely new method from scratch, you can simply compose the method that you already have that's working.
We can use the following method to combine predicates together:
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 secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, secondBody), expr1.Parameters);
}
public static Expression<Func<T, bool>> And<T>(
this Expression<Func<T, bool>> expr1,
Expression<Func<T, bool>> expr2)
{
var secondBody = expr2.Body.Replace(expr2.Parameters[0], expr1.Parameters[0]);
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso(expr1.Body, secondBody), expr1.Parameters);
}
}
It relies on the following method to replace all instance of one expression with another:
public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}
internal class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
Now all we have to do is call the single value version of AnyColumnContains for each value and Or all of the results together:
public static Expression<Func<T, bool>> AnyColumnContains<T>(IEnumerable<string> values)
{
return values.Select(value => AnyColumnContains<T>(value))
.Aggregate((a, b) => a.Or(b));
}
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);
}
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 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));
}