一般如果逻辑比较简单,只是存在有的情况多一个查询条件,有的情况不需要添加该查询条件
简单方式这样操作就可以了
public IQueryable<FileImport> DynamicChainedSyntax (IQueryable<FileImport> files, bool pastOnly) { var query = files.Where(file => file.ImportDate > DateTime.Now.AddDays(-7)); if (pastOnly) query = query.Where(file => file.ImportDate < DateTime.Today); return query; }
这里的多个where条件是AND关系,如果是OR的关系,可将多次查询的结果进行union
当然大多数的时候,我们是希望能够动态构建查询条件的,你可以针对任何字段进行任何操作符形式的查询,不同查询条件之间的关系也是可以动态定义的。
这时候表达式树就派上用场了,关于表达式树的基础知识已经在上一篇中提到了。
这里主要说如何构建linq中Where查询条件,其实只是熟悉表达式树的其他提供的方法,非常简单。
public Func<TSource, bool> SimpleComparison<TSource> string property, object value) { var type = typeof (TSource); var pe = Expression.Parameter(type, "p"); var propertyReference = Expression.Property(pe, property); var constantReference = Expression.Constant(value); return Expression.Lambda<Func<TSource, bool>> (Expression.Equal(propertyReference, constantReference), new[] { pe }).Compile(); }
呵呵,话到这里,看看我的小DEMO
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { //(a,b)=>(a+b) //参数的构建 (定义参数的名字和参数的类型) ParameterExpression exp1 = Expression.Parameter(typeof(int), "a"); ParameterExpression exp2 = Expression.Parameter(typeof(int), "b"); //表达式主体的构建 BinaryExpression exp = Expression.Add(exp1, exp2); //表达式树的构建(如下定义,表达式的类型为Lambda //lambda表达式的类型为Func<int, int, int>) var lambda = Expression.Lambda<Func<int, int, int>>(exp, exp1, exp2); //p=>p.Name 可以动态构建OrderBy ParameterExpression exp3 = Expression.Parameter(typeof(Person), "p"); var property = Expression.Property(exp3, "Name"); var lambda2 = Expression.Lambda<Func<Person, string>>(property, exp3); //p=>p.Name == "daisy" List<Person> persons = new List<Person>() { new Person(){ Name = "daisy", age = 10 }, new Person(){ Name = "daisy", age = 12 }, new Person(){Name="dom", age=12}, new Person(){Name="caren", age=10}}; var compareExp = simpleCompare<Person>("Name", "daisy"); var daisys = persons.Where(compareExp).ToList(); foreach (var item in daisys) { Console.WriteLine("Name: "+item.Name+" Age: "+item.age); } Console.ReadKey(); } public static Func<TSource, bool> simpleCompare<TSource>(string property, object value) { var type = typeof(TSource); var pe = Expression.Parameter(type, "p"); var propertyReference = Expression.Property(pe, property); var constantReference = Expression.Constant(value); //compile 是表达式的一个接口,生成该lambda表达式树对的委托 return Expression.Lambda<Func<TSource, bool>>(Expression.Equal(propertyReference, constantReference), pe).Compile(); } } public class Person { public string Name { get; set; } public int age { get; set; } } }
再来看看查询结果:
嗯,理解起来还是非常简单的,就是构建表达式树,返回我们需要的委托类型!
接下来猛料哦
动态构建表达式树,最佳实践版,很实用!
public class FilterCollection : Collection<IList<Filter>> { public FilterCollection() : base() { } } public class Filter { public string PropertyName { get; set; } public Op Operation { get; set; } public object Value { get; set; } } public enum Op { Equals, GreaterThan, LessThan, GreaterThanOrEqual, LessThanOrEqual, Contains, StartsWith, EndsWith }
通过上面的类可以动态构建复杂的查询条件,下面具体调用的类哦
using Infrastructure.Model; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace Infrastructure.Operation { public static class LambdaExpressionBuilder { private static MethodInfo containsMethod = typeof(string).GetMethod("Contains"); private static MethodInfo startsWithMethod = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }); private static MethodInfo endsWithMethod = typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) }); private static Expression GetExpression(ParameterExpression param, Filter filter) { MemberExpression member = Expression.Property(param, filter.PropertyName); Expression handledMember = member; ConstantExpression constant = Expression.Constant(filter.Value); if (member.Member.MemberType == MemberTypes.Property) { Type propertyType = ((PropertyInfo)member.Member).PropertyType; if (propertyType == typeof(string)) { handledMember = Expression.Call(member, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes)); } if (propertyType == typeof(DateTime?)) { handledMember = Expression.Property(member, typeof(DateTime?).GetProperty("Value")); } } switch (filter.Operation) { case Op.Equals: return Expression.Equal(handledMember, constant); case Op.GreaterThan: return Expression.GreaterThan(handledMember, constant); case Op.GreaterThanOrEqual: return Expression.GreaterThanOrEqual(handledMember, constant); case Op.LessThan: return Expression.LessThan(handledMember, constant); case Op.LessThanOrEqual: return Expression.LessThanOrEqual(handledMember, constant); case Op.Contains: return Expression.Call(handledMember, containsMethod, constant); case Op.StartsWith: return Expression.Call(handledMember, startsWithMethod, constant); case Op.EndsWith: return Expression.Call(handledMember, endsWithMethod, constant); } return null; } private static BinaryExpression GetORExpression(ParameterExpression param, Filter filter1, Filter filter2) { Expression bin1 = GetExpression(param, filter1); Expression bin2 = GetExpression(param, filter2); return Expression.Or(bin1, bin2); } private static Expression GetExpression(ParameterExpression param, IList<Filter> orFilters) { if (orFilters.Count == 0) return null; Expression exp = null; if (orFilters.Count == 1) { exp = GetExpression(param, orFilters[0]); } else if (orFilters.Count == 2) { exp = GetORExpression(param, orFilters[0], orFilters[1]); } else { while (orFilters.Count > 0) { var f1 = orFilters[0]; var f2 = orFilters[1]; if (exp == null) { exp = GetORExpression(param, orFilters[0], orFilters[1]); } else { exp = Expression.Or(exp, GetORExpression(param, orFilters[0], orFilters[1])); } orFilters.Remove(f1); orFilters.Remove(f2); if (orFilters.Count == 1) { exp = Expression.Or(exp, GetExpression(param, orFilters[0])); orFilters.RemoveAt(0); } } } return exp; } public static Expression<Func<T, bool>> GetExpression<T>(FilterCollection filters) { if (filters == null || filters.Count == 0) return null; ParameterExpression param = Expression.Parameter(typeof(T), "t"); Expression exp = null; if (filters.Count == 1) { exp = GetExpression(param, filters[0]); } else if (filters.Count == 2) { exp = Expression.AndAlso(GetExpression(param, filters[0]), GetExpression(param, filters[1])); } else { while (filters.Count > 0) { var f1 = filters[0]; var f2 = filters[1]; var f1Andf2 = Expression.AndAlso(GetExpression(param, filters[0]), GetExpression(param, filters[1])); if (exp == null) { exp = f1Andf2; } else { exp = Expression.AndAlso(exp, f1Andf2); } filters.Remove(f1); filters.Remove(f2); if (filters.Count == 1) { exp = Expression.AndAlso(exp, GetExpression(param, filters[0])); filters.RemoveAt(0); } } } return Expression.Lambda<Func<T, bool>>(exp, param); } } }
再来一个OrderBy动态构建
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; namespace Jurassic.Sooil.Com { public static class OrderExpression { public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property) { return ApplyOrder<T>(source, property, "OrderBy"); } public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property) { return ApplyOrder<T>(source, property, "OrderByDescending"); } public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property) { return ApplyOrder<T>(source, property, "ThenBy"); } public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property) { return ApplyOrder<T>(source, property, "ThenByDescending"); } static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName) { string[] props = property.Split('.'); Type type = typeof(T); ParameterExpression arg = Expression.Parameter(type, "x"); Expression expr = arg; foreach (string prop in props) { // use reflection (not ComponentModel) to mirror LINQ PropertyInfo pi = type.GetProperty(prop); expr = Expression.Property(expr, pi); type = pi.PropertyType; } Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type); LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg); object result = typeof(Queryable).GetMethods().Single( method => method.Name == methodName && method.IsGenericMethodDefinition && method.GetGenericArguments().Length == 2 && method.GetParameters().Length == 2) .MakeGenericMethod(typeof(T), type) .Invoke(null, new object[] { source, lambda }); return (IOrderedQueryable<T>)result; } } }
至此动态构建LINQ查询结束!花了上班时间一上午,还是相当值得的,不过被项目经理知道了得哭死!
不管如何,学到手的才是自己的!
————————————————
版权声明:本文为CSDN博主「GRACE_ETERNITY」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Shiyaru1314/article/details/49508181

