How to make a PredicateBuilder Not - c#

recently I've been working with the PredicateBuilder class (shown here) to help generate an expression tree. The True, And, and Or methods provided work fine. However, I would also like to use a Not method, and so far my attempt at one gets me the error
Incorrect number of parameters supplied for lambda declaration.
Here is said attempt:
public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expr)
{
return Expression.Lambda<Func<T, bool>>
(Expression.Not(Expression.Invoke(expr, expr.Parameters.Cast<Expression>())));
}
Any thoughts?
NB

Oop, just about had it. I wasn't giving parameters to the outer .Lambda function:
public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expr)
{
return Expression.Lambda<Func<T, bool>>
(Expression.Not(Expression.Invoke(expr, expr.Parameters.Cast<Expression>())), expr.Parameters);
}

Related

Extending an access expression to check for value

I'm currently trying to wrestle with expression trees to make a bit of magic happen, but I keep hitting error after error.
I've got some properties like this on some of my domain objects (Entity Framework)
Expression<Func<DomainObject, LinkedDomainObject>> IncludeExpr
{
get {
return o => o.SomeLinkedObject;
}
}
and another expression that checks that linked object for equality on some property (e.g. ID).
I did have an expression that also checked that linked object for being null, and that way I could compose a NotNull and Matched ID expression by inverting the null check expression and combining it via AndAlso with the ID check expression.
I want to take the o => o.SomeLinkedObject expression and linkedObject => linkedObject.ID == idVar expressions and mash them together to effectively get:
o => o.LinkedObject != null && o.LinkedObject.Id == idVar
But I can't for the life of me work out how I'd get an expression tree together based on those two separate expressions.
We can take a moment to create a helper method that can make solving this problem very straightforward. If we create a method that lets us compose expressions as easily as we can compose delegates, this becomes very easy. Our Compose method will accept an expression, and another that takes the output of the first and transforms it into something else, creating a new expression that can transform something of the type of the input of the first into the output of the second:
public static Expression<Func<TFirstParam, TResult>>
Compose<TFirstParam, TIntermediate, TResult>(
this Expression<Func<TFirstParam, TIntermediate>> first,
Expression<Func<TIntermediate, TResult>> second)
{
var param = Expression.Parameter(typeof(TFirstParam), "param");
var newFirst = first.Body.Replace(first.Parameters[0], param);
var newSecond = second.Body.Replace(second.Parameters[0], newFirst);
return Expression.Lambda<Func<TFirstParam, TResult>>(newSecond, param);
}
This is dependent on the following method to replace all instances 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 we can create an IsNotNull transformation very easily:
public static Expression<Func<TSource, bool>> IsNotNull<TSource, TKey>(
this Expression<Func<TSource, TKey>> expression)
{
return expression.Compose(key => key != null);
}
As for And-ing two expressions together, the easiest option if using a LINQ query provider is to just call Where on each expression separately, if that's an option. If not, you can use a PrediacteBuilder to And or Or two expressions 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);
}
}

EF extension method: "This function can only be invoked from LINQ to Entities."

I have made an extension method to EF entities:
public static IEnumerable<T> WildcardSearch<T>(this IEnumerable<T> entity,
string param, Func<T,
string> selector)
{
return entity.Where(l => SqlFunctions.PatIndex(param, selector(l)) > 0);
}
//exception: This function can only be invoked from LINQ to Entities.
result = context.FOO.WildcardSearch(id, x => x.Id).ToList();
I get the exception above if I try to use it.
However, if I run (what I assume) the very same code directly on my collection, it works as intented.
Why do I get the exception, and is there any way to fix this?
Similar threads suggest changing the type to IQueryable, but it doesn't seem to help.
//this works
result = context.FOO.Where(x =>
SqlFunctions.PatIndex(id, x.Id) > 0).ToList();
It needs to be IQueryable<T> and Expression<Func<...>>; unfortunately this means rebuilding the expression tree - for example:
public static IQueryable<T> WildcardSearch<T>(this IQueryable<T> entity,
string param, Expression<Func<T, string>> selector)
{
var lambda = Expression.Lambda<Func<T, bool>>(
Expression.GreaterThan(
Expression.Call(
typeof(SqlFunctions), "PatIndex", null,
Expression.Constant(param, typeof(string)),
selector.Body),
Expression.Constant(0)),
selector.Parameters);
return entity.Where(lambda);
}

Convert Predicate<T> to Expression<Func<T, bool>>

Is possible to convert a Predicate<T> to Expression<Func<T, bool>> in some way?
I would like to use the next IQueryable function using the filters of the my ICollectionView:
public static System.Linq.IQueryable<TSource> Where<TSource>(this System.Linq.IQueryable<TSource> source, System.Linq.Expressions.Expression<System.Func<TSource, bool>> predicate)
Thanks
Something like this?
Predicate<string> predicate = input => input.Length > 0;
Expression<Func<string, bool>> expression = (input) => predicate(input);
You can probably make an extension Where method for your ICollectionView which takes a predicate, converts it to an Expression like this, and then call the Where method provided by Linq.
public static IQueryable<T> Where(this IQueryable<T> source, Predicate<T> predicate)
{
return source.Where(x => predicate(x));
}
In theory it is possible to convert a delegate 'back' to an expression, because you can request the emitted IL of a delegate, which gives you the information you need to transform it back.
However, it's for a reason that neither LINQ to SQL and Entity Framework do this. It is complex, fragile, and performance intensive to do so.
So the short answer is, you can't transform it to an expression.
namespace ConsoleApplication1
{
static class Extensions
{
public static Expression<Func<T, bool>> ToExpression<T>(this Predicate<T> p)
{
ParameterExpression p0 = Expression.Parameter(typeof(T));
return Expression.Lambda<Func<T, bool>>(Expression.Call(p.Method, p0),
new ParameterExpression[] { p0 });
}
}
}

Create a Linq Expression with StartsWith, EndsWith and Contains passing a Expression<Func<T, string>>

I want to create a method passing a expression of type Expression<Func<T, string> to create expression of type Expression<Func<T, bool>> to filter a string property with the StartsWith, EndsWith and Contains methods like these expressions:
.Where(e => e.MiProperty.ToUpper().StartsWith("ABC"));
.Where(e => e.MiProperty.ToUpper().EndsWith("XYZ"));
.Where(e => e.MiProperty.ToUpper().Contains("MNO"));
the method should look like:
public Expression<Func<T, bool>> AddFilterToStringProperty<T>(Expresssion<Func<T, string>> pMyExpression, string pFilter, FilterType pFiltertype)
where FilterType is an enum type that contains the three of the mentioned operations (StartsWith, EndsWith, Contains)
Try this:
public static Expression<Func<T, bool>> AddFilterToStringProperty<T>(
Expression<Func<T, string>> expression, string filter, FilterType type)
{
return Expression.Lambda<Func<T, bool>>(
Expression.Call(
expression.Body,
type.ToString(),
null,
Expression.Constant(filter)),
expression.Parameters);
}
Thanks #dtb. It works fine and I added a "not null" expression for this case like this:
public static Expression<Func<T, bool>> AddFilterToStringProperty2<T>(
Expression<Func<T, string>> expression, string filter, FilterType type)
{
var vNotNullExpresion = Expression.NotEqual(
expression.Body,
Expression.Constant(null));
var vMethodExpresion = Expression.Call(
expression.Body,
type.ToString(),
null,
Expression.Constant(filter));
var vFilterExpresion = Expression.AndAlso(vNotNullExpresion, vMethodExpresion);
return Expression.Lambda<Func<T, bool>>(
vFilterExpresion,
expression.Parameters);
}

Linq - Creating Expression<T1> from Expression<T2>

I have a predicate Expression<Func<T1, bool>>
I need to use it as a predicate Expression<Func<T2, bool>> using the T1 property of T2 I was trying to think about several approches, probably using Expression.Invoke but couln;t get my head around it.
For reference:
class T2 {
public T1 T1;
}
And
Expression<Func<T1, bool>> ConvertPredicates(Expression<Func<T2, bool>> predicate) {
//what to do here...
}
Thanks a lot in advance.
Try to find the solution with normal lambdas before you think about expression trees.
You have a predicate
Func<T1, bool> p1
and want a predicate
Func<T2, bool> p2 = (x => p1(x.T1));
You can build this as an expression tree as follows:
Expression<Func<T2, bool>> Convert(Expression<Func<T1, bool>> predicate)
{
var x = Expression.Parameter(typeof(T2), "x");
return Expression.Lambda<Func<T2, bool>>(
Expression.Invoke(predicate, Expression.PropertyOrField(x, "T1")), x);
}

Categories