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);
}
}
Related
What is happening is when the value, per example, kitefiltered.MarcaId == null (the user left empty), this query check if the value is null. But is not what I want. I just want to check if the value inserted != null (new value), and if its null, jump to the next where clause.
I donĀ“t think the best solution its check before, because are many values to check.
var kitecadastrado = db.KiteCadastrados.Where(f => ((f.MarcaId == kitefiltered.MarcaId) &&
(f.ModeloId == kitefiltered.ModeloId)&&(f.NumSerie == kitefiltered.NumSerie) &&...
EDIT 1:
To clarify my question. I want If kitefiltered.MarcaId != null, TEST (f.MarcaId == kitefiltered.MarcaId) ELSE JUMP TO NEXT CLAUSE && ....
Thanks.
NULL coalesce can have surprising results in LINQ to entities/SQL. SQL does not treat NULL the same way C# does. != NULL seems to translate well.
If I follow you correctly, the main issue is that you are filtering by NULL in cases where you don't want to be. That can be especially tricky because of the SQL translations I mentioned. I recommend using PredicateBuilder to build up your predicates using Expressions. This works on my machine, but it's tough to test because I don't have your context or EF setup on my machine.
You may need to use AsExpandable() from LINQKit because you are working with EF.
void Main()
{
var predicate = PredicateBuilder.True<KiteCadastrado>();
var filter = new KiteFilter();//your kitefiltered object
filter.MarcaId = "98272";//fill in your own values here
filter.NumSerie = "Unit E";
if(filter.MarcaId != null){
predicate = predicate.And(p => p.MarcaId == filter.MarcaId);
}
if(filter.NumSerie != null){
predicate = predicate.And(p => p.NumSerie == filter.NumSerie);
}
//fill out remaining values
db.KiteCadastrados.AsExpandable().Where(predicate).Count();//Added AsExpandable()
}
public class KiteFilter
{
public String MarcaId { get; set; }
public String NumSerie { get; set; }
}
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);
}
}
This way you don't have to include the NULLs in the LINQ expression directly. And you will ultimately end up with a leaner and more flexible expression overall.
Look into null coalescence for Linq statements. This question here might have the answer you need as I don't have a data set ready to rest with.
This question is the question in question
I couldn't think of a better way to word the question, but what I'm trying to do is reduce the signature of a LambdaExpression from Expression<Func<MyObject, FilterObject, bool>> to Expression<Func<MyObject, bool>> by handling the instance of the FilterObject before the LambdaExpression is evaluated.
Here's a quick example:
AddFilter("Filter Name", FilterTypes.All,
(x, y) => GetConjunctionResult(
x.PersonA.IsSomething, x.PersonB.IsSomething, y.ConjunctionType));
private static bool GetConjunctionResult(bool personA, bool personB,
ConjunctionType conjunctionType)
{
switch (conjunctionType)
{
case ConjunctionType.Both:
return personA && personB:
case ConjunctionType.Either:
return personA && personB;
case ConjunctionType.PersonA:
return personA;
case ConjunctionType.PersonB:
return personB;
case ConjunctionType.Neither:
return !personA && !personB;
}
}
So I want this overload of AddFilter to create an object of type FilterObject and embed it into a LambdaExpression along the lines of:
var filter = new FilterObject();
// create Expression<Func<MyObject, bool>> lambda = x => GetConjunctionResult(
// x.PersonA.IsSomething, x.PersonB.IsSomething, filter.ConjunctionType));
Now there might be a better way to do this, so I'm open to any suggestions that eschew this approach altogether.
Given
var filter = new FilterObject()
it should be:
Expression<Func<MyObject, bool>> exp2 =
Expression.Lambda<Func<MyObject, bool>>(
Expression.Invoke(myExp,
myExp.Parameters[0],
Expression.Constant(filter)),
myExp.Parameters[0]);
Expression.Invoke will call the other expression and pass as the first parameter the first parameter of the new expression, and as the second parameter an Expression.Constant with your filter.
Are you trying to use Currying with Expression trees?
A better approach than calling Invoke is to substitute the parameter in the Expression tree directly using a ExpressionVisitor. You can define a couple of simple extension methods to make this easy. In this case they can apply the first parameter of the expression (you'd need to change your signature or adapt them to apply a middle parameter).
Usage:
var applied = expr.Apply(constValueForFirstParameter);
In a static class define these extension methods:
public static Expression<Func<U, V, bool>> Apply<T, U, V>(this Expression<Func<T, U, V, bool>> input, T value)
{
var swap = new ExpressionSubstitute(input.Parameters[0], Expression.Constant(value));
var lambda = Expression.Lambda<Func<U, V, bool>>(swap.Visit(input.Body), input.Parameters[1], input.Parameters[2]);
return lambda;
}
public static Expression<Func<U, bool>> Apply<T, U>(this Expression<Func<T, U, bool>> input, T value)
{
var swap = new ExpressionSubstitute(input.Parameters[0], Expression.Constant(value));
var lambda = Expression.Lambda<Func<U, bool>>(swap.Visit(input.Body), input.Parameters[1]);
return lambda;
}
class ExpressionSubstitute : System.Linq.Expressions.ExpressionVisitor
{
private readonly Expression from, to;
public ExpressionSubstitute(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
if (node == from) return to;
return base.Visit(node);
}
}
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);
}
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 });
}
}
}
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);
}