using System; using System.Collections.ObjectModel; using System.Linq.Expressions; using System.Reflection; namespace wispro.sp.utility { public class Query { public enum Operators { None = 0, Equal = 1, GreaterThan = 2, GreaterThanOrEqual = 3, LessThan = 4, LessThanOrEqual = 5, Contains = 6, StartWith = 7, EndWidth = 8, Range = 9 } public enum Condition { OrElse = 1, AndAlso = 2 } public string Name { get; set; } public Operators Operator { get; set; } public object Value { get; set; } public object ValueMin { get; set; } public object ValueMax { get; set; } public class QueryCollection : Collection { public Expression> AsExpression(Query.Condition? condition = Query.Condition.OrElse) where T : class { Type targetType = typeof(T); TypeInfo typeInfo = targetType.GetTypeInfo(); var parameter = Expression.Parameter(targetType, "m"); Expression expression = null; Func Append = (exp1, exp2) => { if (exp1 == null) { return exp2; } return (condition ?? Query.Condition.OrElse) == Query.Condition.OrElse ? Expression.OrElse(exp1, exp2) : Expression.AndAlso(exp1, exp2); }; foreach (var item in this) { var property = typeInfo.GetProperty(item.Name); if (property == null || !property.CanRead || (item.Operator != Query.Operators.Range && item.Value == null) || (item.Operator == Query.Operators.Range && item.ValueMin == null && item.ValueMax == null)) { continue; } Type realType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType; if (item.Value != null) { item.Value = Convert.ChangeType(item.Value, realType); } Expression> valueLamba = () => item.Value; switch (item.Operator) { case Query.Operators.Equal: { expression = Append(expression, Expression.Equal(Expression.Property(parameter, item.Name), Expression.Convert(valueLamba.Body, property.PropertyType))); break; } case Query.Operators.GreaterThan: { expression = Append(expression, Expression.GreaterThan(Expression.Property(parameter, item.Name), Expression.Convert(valueLamba.Body, property.PropertyType))); break; } case Query.Operators.GreaterThanOrEqual: { expression = Append(expression, Expression.GreaterThanOrEqual(Expression.Property(parameter, item.Name), Expression.Convert(valueLamba.Body, property.PropertyType))); break; } case Query.Operators.LessThan: { expression = Append(expression, Expression.LessThan(Expression.Property(parameter, item.Name), Expression.Convert(valueLamba.Body, property.PropertyType))); break; } case Query.Operators.LessThanOrEqual: { expression = Append(expression, Expression.LessThanOrEqual(Expression.Property(parameter, item.Name), Expression.Convert(valueLamba.Body, property.PropertyType))); break; } case Query.Operators.Contains: { var nullCheck = Expression.Not(Expression.Call(typeof(string), "IsNullOrEmpty", null, Expression.Property(parameter, item.Name))); var contains = Expression.Call(Expression.Property(parameter, item.Name), "Contains", null, Expression.Convert(valueLamba.Body, property.PropertyType)); expression = Append(expression, Expression.AndAlso(nullCheck, contains)); break; } case Query.Operators.StartWith: { var nullCheck = Expression.Not(Expression.Call(typeof(string), "IsNullOrEmpty", null, Expression.Property(parameter, item.Name))); var startsWith = Expression.Call(Expression.Property(parameter, item.Name), "StartsWith", null, Expression.Convert(valueLamba.Body, property.PropertyType)); expression = Append(expression, Expression.AndAlso(nullCheck, startsWith)); break; } case Query.Operators.EndWidth: { var nullCheck = Expression.Not(Expression.Call(typeof(string), "IsNullOrEmpty", null, Expression.Property(parameter, item.Name))); var endsWith = Expression.Call(Expression.Property(parameter, item.Name), "EndsWith", null, Expression.Convert(valueLamba.Body, property.PropertyType)); expression = Append(expression, Expression.AndAlso(nullCheck, endsWith)); break; } case Query.Operators.Range: { Expression minExp = null, maxExp = null; if (item.ValueMin != null) { var minValue = Convert.ChangeType(item.ValueMin, realType); Expression> minValueLamda = () => minValue; minExp = Expression.GreaterThanOrEqual(Expression.Property(parameter, item.Name), Expression.Convert(minValueLamda.Body, property.PropertyType)); } if (item.ValueMax != null) { var maxValue = Convert.ChangeType(item.ValueMax, realType); Expression> maxValueLamda = () => maxValue; maxExp = Expression.LessThanOrEqual(Expression.Property(parameter, item.Name), Expression.Convert(maxValueLamda.Body, property.PropertyType)); } if (minExp != null && maxExp != null) { expression = Append(expression, Expression.AndAlso(minExp, maxExp)); } else if (minExp != null) { expression = Append(expression, minExp); } else if (maxExp != null) { expression = Append(expression, maxExp); } break; } } } if (expression == null) { return null; } return ((Expression>)Expression.Lambda(expression, parameter)); } } } }