I am creating a way for users to filter results based on start and end values. An example of this would be:?RangeColumn=DisplayId&RangeStart=640,830,670&RangeEnd=650,850,680In this case, the api would return items where the DisplayId is between 640-650 or 830-850 or 670-680. My solution works but the query looks pretty bad:{t => ((((t.DisplayId >= { Item = 640 }.Item) AndAlso (t.DisplayId <= { Item = 650 }.Item)) OrElse ((t.DisplayId >= { Item = 830 }.Item) AndAlso (t.DisplayId <= { Item = 850 }.Item))) OrElse ((t.DisplayId >= { Item = 670 }.Item) AndAlso (t.DisplayId <= { Item = 680 }.Item)))}The user can have an unlimited number of ranges so this could quickly get crazy really fast so I'm wondering if there is a better way for me to do what I am trying to do. Here are the methods that are relevant to the problem:private static IQueryable<T> FilterOnRange<T>(Type entityType, RangeProperties rangeProperties, IQueryable<T> query)    {        var startCount = rangeProperties.RangeStart.Count();        var endCount = rangeProperties.RangeEnd.Count();        if (startCount > 0 || endCount > 0)        {            if (startCount != endCount && (startCount > 1 || endCount > 1))                throw new RangeFilterException();        }        else            return query;        PropertyInfo pi = GetFilterPropertyInfo(entityType, rangeProperties.RangeColumnName);        if (pi != null)        {            bool propertyIsNullableType = pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>));            bool isInteger = pi.PropertyType.Equals(typeof(int)) || (propertyIsNullableType && Nullable.GetUnderlyingType(pi.PropertyType).Equals(typeof(int)));            bool isDateTimeOffset = pi.PropertyType.Equals(typeof(DateTimeOffset)) || (propertyIsNullableType && Nullable.GetUnderlyingType(pi.PropertyType).Equals(typeof(DateTimeOffset)));            var maxCount = Math.Max(startCount, endCount);            ParameterExpression argParam = Expression.Parameter(typeof(T), t);            if (isInteger)            {                if (maxCount == 1)                {                    string start = startCount > 0 ? rangeProperties.RangeStart.Single() : null;                    string end = endCount > 0 ? rangeProperties.RangeEnd.Single() : null;                    var lambda = RangeInt<T>(argParam, start, end, rangeProperties.RangeColumnName, propertyIsNullableType);                    query = query.Where(lambda);                }                else                {                    Expression<Func<T, bool>> outerLambda = null;                    for (int i = 0; i < maxCount; i++)                    {                        string start = rangeProperties.RangeStart[i];                        string end = rangeProperties.RangeEnd[i];                        var lambda1 = RangeInt<T>(argParam, start, end, rangeProperties.RangeColumnName, propertyIsNullableType);                        Expression<Func<T, bool>> tempLambda = null;                        i++;                        if (i >= maxCount)                        {                            tempLambda = lambda1;                        }                        else                        {                            start = rangeProperties.RangeStart[i];                            end = rangeProperties.RangeEnd[i];                            var lambda2 = RangeInt<T>(argParam, start, end, rangeProperties.RangeColumnName, propertyIsNullableType);                            var body = Expression.OrElse(lambda1.Body, lambda2.Body);                            tempLambda = Expression.Lambda<Func<T, bool>>(body, lambda1.Parameters[0]);                        }                        if (outerLambda == null)                            outerLambda = tempLambda;                        else                        {                            var body = Expression.OrElse(outerLambda.Body, tempLambda.Body);                            outerLambda = Expression.Lambda<Func<T, bool>>(body, outerLambda.Parameters[0]);                        }                    }                    query = query.Where(outerLambda);                }            }            else if (isDateTimeOffset)            {                if (maxCount == 1)                {                    string start = startCount > 0 ? rangeProperties.RangeStart.Single() : null;                    string end = endCount > 0 ? rangeProperties.RangeEnd.Single() : null;                    var lambda = RangeDateTime<T>(argParam, start, end, rangeProperties.RangeColumnName, propertyIsNullableType);                    query = query.Where(lambda);                }                else                {                    Expression<Func<T, bool>> outerLambda = null;                    for (int i = 0; i < maxCount; i++)                    {                        string start = rangeProperties.RangeStart[i];                        string end = rangeProperties.RangeEnd[i];                        var lambda1 = RangeDateTime<T>(argParam, start, end, rangeProperties.RangeColumnName, propertyIsNullableType);                        Expression<Func<T, bool>> tempLambda = null;                        i++;                        if (i >= maxCount)                        {                            tempLambda = lambda1;                        }                        else                        {                            start = rangeProperties.RangeStart[i];                            end = rangeProperties.RangeEnd[i];                            var lambda2 = RangeDateTime<T>(argParam, start, end, rangeProperties.RangeColumnName, propertyIsNullableType);                            var body = Expression.OrElse(lambda1.Body, lambda2.Body);                            tempLambda = Expression.Lambda<Func<T, bool>>(body, lambda1.Parameters[0]);                        }                        if (outerLambda == null)                            outerLambda = tempLambda;                        else                        {                            var body = Expression.OrElse(outerLambda.Body, tempLambda.Body);                            outerLambda = Expression.Lambda<Func<T, bool>>(body, outerLambda.Parameters[0]);                        }                    }                    query = query.Where(outerLambda);                }            }            else                throw new InvalidOperationException(Only Datetime and Integer is supported for a range filter.);        }        return query;    }    private static Expression<Func<T, bool>> RangeInt<T>(ParameterExpression argParam, string start, string end, string columnName, bool propertyIsNullableType)    {        int? rangeStart = null;        int tempRangeStart = int.MinValue;        if (int.TryParse(start, out tempRangeStart))            rangeStart = tempRangeStart;        else            rangeStart = int.MinValue;        int? rangeEnd = null;        int tempRangeEnd = int.MaxValue;        if (int.TryParse(end, out tempRangeEnd))            rangeEnd = tempRangeEnd;        else            rangeEnd = int.MaxValue;        if (rangeEnd < rangeStart)            throw new InvalidOperationException(RangeEnd must be greater than RangeStart.);        Expression rangeProperty = Expression.Property(argParam, columnName);        MemberExpression comparisonValue2 = null;        if (propertyIsNullableType)        {            var item = new { Item = (int?)rangeStart };            var comparisonValue = Expression.Constant(item);            comparisonValue2 = Expression.MakeMemberAccess(comparisonValue, item.GetType().GetMember(Item).First());        }        else        {            var item = new { Item = (int)rangeStart };            var comparisonValue = Expression.Constant(item);            comparisonValue2 = Expression.MakeMemberAccess(comparisonValue, item.GetType().GetMember(Item).First());        }        Expression e1 = Expression.GreaterThanOrEqual(rangeProperty, comparisonValue2);        MemberExpression comparisonValue4 = null;        if (propertyIsNullableType)        {            var item2 = new { Item = (int?)rangeEnd };            var comparisonValue3 = Expression.Constant(item2);            comparisonValue4 = Expression.MakeMemberAccess(comparisonValue3, item2.GetType().GetMember(Item).First());        }        else        {            var item2 = new { Item = (int)rangeEnd };            var comparisonValue3 = Expression.Constant(item2);            comparisonValue4 = Expression.MakeMemberAccess(comparisonValue3, item2.GetType().GetMember(Item).First());        }        Expression e2 = Expression.LessThanOrEqual(rangeProperty, comparisonValue4);        Expression e3 = Expression.AndAlso(e1, e2);        return Expression.Lambda<Func<T, bool>>(e3, argParam);    }    private static Expression<Func<T, bool>> RangeDateTime<T>(ParameterExpression argParam, string start, string end, string columnName, bool propertyIsNullableType)    {        DateTimeOffset? rangeStart = null;        DateTimeOffset tempRangeStart = DateTimeOffset.MinValue;        if (DateTimeOffset.TryParse(start, out tempRangeStart))            rangeStart = tempRangeStart;        else            rangeStart = DateTimeOffset.MinValue;        DateTimeOffset? rangeEnd = null;        DateTimeOffset tempRangeEnd = DateTimeOffset.MaxValue;        if (DateTimeOffset.TryParse(end, out tempRangeEnd))            rangeEnd = tempRangeEnd;        else            rangeEnd = DateTimeOffset.MaxValue;        if (rangeEnd < rangeStart)            throw new InvalidOperationException(RangeEnd must be greater than RangeStart.);        Expression rangeProperty = Expression.Property(argParam, columnName);        MemberExpression comparisonValue2 = null;        if (propertyIsNullableType)        {            var item = new { Item = (DateTimeOffset?)rangeStart };            var comparisonValue = Expression.Constant(item);            comparisonValue2 = Expression.MakeMemberAccess(comparisonValue, item.GetType().GetMember(Item).First());        }        else        {            var item = new { Item = (DateTimeOffset)rangeStart };            var comparisonValue = Expression.Constant(item);            comparisonValue2 = Expression.MakeMemberAccess(comparisonValue, item.GetType().GetMember(Item).First());        }        Expression e1 = Expression.GreaterThanOrEqual(rangeProperty, comparisonValue2);        MemberExpression comparisonValue4 = null;        if (propertyIsNullableType)        {            var item2 = new { Item = (DateTimeOffset?)rangeEnd };            var comparisonValue3 = Expression.Constant(item2);            comparisonValue4 = Expression.MakeMemberAccess(comparisonValue3, item2.GetType().GetMember(Item).First());        }        else        {            var item2 = new { Item = (DateTimeOffset)rangeEnd };            var comparisonValue3 = Expression.Constant(item2);            comparisonValue4 = Expression.MakeMemberAccess(comparisonValue3, item2.GetType().GetMember(Item).First());        }        Expression e2 = Expression.LessThanOrEqual(rangeProperty, comparisonValue4);        Expression e3 = Expression.AndAlso(e1, e2);        return Expression.Lambda<Func<T, bool>>(e3, argParam);    }
Building expression tree with multiple OrElse
c#;linq;entity framework;expression trees