Daniil T.
Daniil T.

Reputation: 1165

Combining expressions to return one expression for query

I faced a little bit problem with Expression<>.

Is it possible to combine more than 2 expression in to one? Example:

Expression<Func<Event, bool>> searchForLogCorrelationKeyExpression =
            x => string.Equals(x.LOG_CORR_KEY, model.CorrelationKey, StringComparison.CurrentCultureIgnoreCase);
        Expression<Func<Event, bool>> searchForLsidExpressionExpression =
            x => string.Equals(x.LOG_LSID, model.LsId, StringComparison.CurrentCultureIgnoreCase);
        Expression<Func<Event, bool>> searchForLogLocationExpression =
            x => string.Equals(x.LOG_LOCATION, model.LogLocation, StringComparison.CurrentCultureIgnoreCase);
        Expression<Func<Event, bool>> searchForLogTypeExpression =
            x => string.Equals(x.LOG_TP, model.LogType.ToString(), StringComparison.CurrentCultureIgnoreCase);
        if (model.EndDateTime != null && model.StartDateTime != null)
        {
            Expression<Func<Event, bool>> searchForLogInDateRangeExpression =
                x => model.StartDateTime <= x.LOG_TS && model.EndDateTime <= x.LOG_TS;
        }   
        Expression<Func<Event, bool>> searchForLogByUserIdExpression =
            x => string.Equals(x.LOG_USERID, model.UserId.ToString(), StringComparison.CurrentCultureIgnoreCase);

        Expression<Func<Event, bool>> searchForLogByLogTextExpression =
            x => string.Equals(x.LOG_TXT, model.SearchString.ToString(), StringComparison.CurrentCultureIgnoreCase);

I have 7 expressions that I want to combine in to one and then put it to the method that accepts Expression<Func<Event, bool>> as a parameter.

Is it possible? I found many example with combining two expressions but they didn't work.

Upvotes: 0

Views: 103

Answers (1)

MistyK
MistyK

Reputation: 6222

Fiddle: https://dotnetfiddle.net/V7Ol0J

Source of knowledge: https://www.codeproject.com/Articles/895951/Combining-expressions-to-dynamically-append-criter

Here is a working example:

   public class Event
    {
        public string A {get;set;}
        public string B {get;set;}
        public string C {get;set;}
    }




public static class Extensions
{
    public static Expression<Func<T, Boolean>> AndAlso<T>(this Expression<Func<T, Boolean>> left, Expression<Func<T, Boolean>> right)
        {
            Expression<Func<T, Boolean>> combined = Expression.Lambda<Func<T, Boolean>>(
                Expression.AndAlso(
                    left.Body,
                    new ExpressionParameterReplacer(right.Parameters, left.Parameters).Visit(right.Body)
                    ), left.Parameters);

                     return combined;
        }
    }



    public class ExpressionParameterReplacer : ExpressionVisitor
    {
        private IDictionary<ParameterExpression, ParameterExpression> ParameterReplacements { get; set; }

        public ExpressionParameterReplacer(IList<ParameterExpression> fromParameters, IList<ParameterExpression> toParameters)
        {
            ParameterReplacements = new Dictionary<ParameterExpression, ParameterExpression>();

            for(int i = 0; i != fromParameters.Count && i != toParameters.Count; i++)
            { ParameterReplacements.Add(fromParameters[i], toParameters[i]); }
        }

        protected override Expression VisitParameter(ParameterExpression node)
        {
            ParameterExpression replacement;

            if(ParameterReplacements.TryGetValue(node, out replacement))
            { node = replacement; }

            return base.VisitParameter(node);
        }           
    }

Usage:

            Expression<Func<Event, bool>> searchForLogCorrelationKeyExpression = x => string.Equals(x.A, "A", StringComparison.CurrentCultureIgnoreCase);
            Expression<Func<Event, bool>> searchForLsidExpressionExpression =  x => string.Equals(x.B, "B", StringComparison.CurrentCultureIgnoreCase);
            Expression<Func<Event, bool>> searchForLogLocationExpression = x => string.Equals(x.C, "C", StringComparison.CurrentCultureIgnoreCase);

            var res = searchForLogCorrelationKeyExpression.AndAlso(searchForLsidExpressionExpression).AndAlso(searchForLogLocationExpression);

            Console.WriteLine(res.Compile()(new Event(){A="A",B="B",C="C"}));

Upvotes: 1

Related Questions