1
votes

I have the next class structure:

    public class Order
    {
        public User User { get; set; }
        public string Name { get; set; }
    }

    public class Authentication
    {
        public string Email { get; set; }      
    }

    public class User
    {
        public string Name { get; set; }
        public List<Authentication> Auths { get; set; }
    }

I'm trying to build an expression at runtime to search entities by User.Name, Order.Name or User.Auths.Email

There are three expressions I'm trying to combine:

    Expression<Func<Order, bool>> usernameExpression = order => order.Name.Contains(searchValue);
    Expression<Func<Order, bool>> nameExpression = order => order.User.Name.Contains(searchValue);
    Expression<Func<Order, bool>> emailExpression = order => order.User.Auths.Any(auth => auth.Email.Contains(searchValue));

I successfully combined two first expressions using ParameterReplacer from this thread: How to Combine two lambdas

However, when combining resulting expression with email expression I get the next error:

Property 'System.String Email' is not defined for type Order'

Looks like the scope doesn't know anything about inner 'auth' parameter. Is it possible to creeate the expression without rebuilding it from scratch?

1
Post your attempt at the combinationCathalMF
You say that you want to combine the, but how do you want to combine them? What expression are you trying to end up with?Servy
@Servy, I was trying to combine them using OrAlso\AndAlso clause. The link to the helper from Ivan's post resolved the issueRefraction
@Refraction That doesn't answer the question of how, specifically, you want to combine them, and what, exactly, you want the examples you provided to produce.Servy

1 Answers

4
votes

The ParameterReplacer you have used is too simplified and blindly replaces every parameter.

Use this instead:

public static class ExpressionUtils
{
    public static Expression ReplaceParameter(this Expression expression, ParameterExpression source, Expression target)
    {
        return new ParameterReplacer { Source = source, Target = target }.Visit(expression);
    }

    class ParameterReplacer : ExpressionVisitor
    {
        public ParameterExpression Source;
        public Expression Target;
        protected override Expression VisitParameter(ParameterExpression node)
        {
            return node == Source ? Target : base.VisitParameter(node);
        }
    }
}

Or use this or this predicate builder helpers.