zoukankan      html  css  js  c++  java
  • c#——表达式树在LINQ动态查询

    一般如果逻辑比较简单,只是存在有的情况多一个查询条件,有的情况不需要添加该查询条件

    简单方式这样操作就可以了

    [csharp] view plain copy
     
    1. public IQueryable<FileImport> DynamicChainedSyntax  
    2.         (IQueryable<FileImport> files, bool pastOnly)  
    3. {  
    4.     var query = files.Where(file => file.ImportDate >  
    5.                 DateTime.Now.AddDays(-7));  
    6.     if (pastOnly)  
    7.         query = query.Where(file => file.ImportDate <  
    8.                 DateTime.Today);  
    9.     return query;  
    10. }  


    这里的多个where条件是AND关系,如果是OR的关系,可将多次查询的结果进行union

    当然大多数的时候,我们是希望能够动态构建查询条件的,你可以针对任何字段进行任何操作符形式的查询,不同查询条件之间的关系也是可以动态定义的。

    这时候表达式树就派上用场了,关于表达式树的基础知识已经在上一篇中提到了。

    这里主要说如何构建linq中Where查询条件,其实只是熟悉表达式树的其他提供的方法,非常简单。

    [csharp] view plain copy
     
    1. public Func<TSource, bool> SimpleComparison<TSource>              
    2.             string property, object value)  
    3. {  
    4.     var type = typeof (TSource);  
    5.     var pe = Expression.Parameter(type, "p");  
    6.     var propertyReference = Expression.Property(pe, property);  
    7.     var constantReference = Expression.Constant(value);  
    8.     return Expression.Lambda<Func<TSource, bool>>  
    9.         (Expression.Equal(propertyReference, constantReference),  
    10.         new[] { pe }).Compile();  
    11. }  

    呵呵,话到这里,看看我的小DEMO

    [csharp] view plain copy
     
    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.Linq;  
    4. using System.Linq.Expressions;  
    5. using System.Text;  
    6. using System.Threading.Tasks;  
    7.   
    8. namespace ConsoleApplication1  
    9. {  
    10.     class Program  
    11.     {  
    12.         static void Main(string[] args)  
    13.         {  
    14.             //(a,b)=>(a+b)  
    15.             //参数的构建  (定义参数的名字和参数的类型)  
    16.             ParameterExpression exp1 = Expression.Parameter(typeof(int), "a");  
    17.             ParameterExpression exp2 = Expression.Parameter(typeof(int), "b");  
    18.             //表达式主体的构建   
    19.             BinaryExpression exp = Expression.Add(exp1, exp2);  
    20.             //表达式树的构建(如下定义,表达式的类型为Lambda   
    21.             //lambda表达式的类型为Func<int, int, int>)  
    22.             var lambda = Expression.Lambda<Func<int, int, int>>(exp, exp1, exp2);  
    23.   
    24.             //p=>p.Name 可以动态构建OrderBy  
    25.             ParameterExpression exp3 = Expression.Parameter(typeof(Person), "p");  
    26.             var property = Expression.Property(exp3, "Name");  
    27.             var lambda2 = Expression.Lambda<Func<Person, string>>(property, exp3);  
    28.   
    29.             //p=>p.Name == "daisy"   
    30.             List<Person> persons = new List<Person>()   
    31.             { new Person(){ Name = "daisy", age = 10 },  
    32.               new Person(){ Name = "daisy", age = 12 },   
    33.               new Person(){Name="dom", age=12},  
    34.               new Person(){Name="caren", age=10}};  
    35.             var compareExp = simpleCompare<Person>("Name", "daisy");  
    36.             var daisys = persons.Where(compareExp).ToList();  
    37.             foreach (var item in daisys)  
    38.             {  
    39.                 Console.WriteLine("Name:  "+item.Name+"    Age:  "+item.age);  
    40.             }  
    41.             Console.ReadKey();  
    42.         }  
    43.         public static Func<TSource, bool> simpleCompare<TSource>(string property, object value)  
    44.         {  
    45.             var type = typeof(TSource);  
    46.             var pe = Expression.Parameter(type, "p");  
    47.             var propertyReference = Expression.Property(pe, property);  
    48.             var constantReference = Expression.Constant(value);  
    49.   
    50.             //compile 是表达式的一个接口,生成该lambda表达式树对的委托  
    51.             return Expression.Lambda<Func<TSource, bool>>(Expression.Equal(propertyReference, constantReference), pe).Compile();  
    52.         }  
    53.   
    54.     }  
    55.     public class Person  
    56.     {  
    57.         public string Name { get; set; }  
    58.         public int age { get; set; }  
    59.     }  
    60. }  


    再来看看查询结果:

    嗯,理解起来还是非常简单的,就是构建表达式树,返回我们需要的委托类型!

    接下来猛料哦

    动态构建表达式树,最佳实践版,很实用!

    [csharp] view plain copy
     
    1. public class FilterCollection : Collection<IList<Filter>>  
    2.    {  
    3.        public FilterCollection()  
    4.            : base()  
    5.        { }  
    6.    }  
    7.   
    8.    public class Filter  
    9.    {  
    10.        public string PropertyName { get; set; }  
    11.        public Op Operation { get; set; }  
    12.        public object Value { get; set; }  
    13.    }  
    14.   
    15.    public enum Op  
    16.    {  
    17.        Equals,  
    18.        GreaterThan,  
    19.        LessThan,  
    20.        GreaterThanOrEqual,  
    21.        LessThanOrEqual,  
    22.        Contains,  
    23.        StartsWith,  
    24.        EndsWith  
    25.    }  


    通过上面的类可以动态构建复杂的查询条件,下面具体调用的类哦

    [csharp] view plain copy
     
    1. using Infrastructure.Model;  
    2. using System;  
    3. using System.Collections.Generic;  
    4. using System.Linq;  
    5. using System.Linq.Expressions;  
    6. using System.Reflection;  
    7. using System.Text;  
    8. using System.Threading.Tasks;  
    9.   
    10. namespace Infrastructure.Operation  
    11. {  
    12.     public static class LambdaExpressionBuilder  
    13.     {  
    14.         private static MethodInfo containsMethod = typeof(string).GetMethod("Contains");  
    15.         private static MethodInfo startsWithMethod =  
    16.                                 typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });  
    17.         private static MethodInfo endsWithMethod =  
    18.                                 typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) });  
    19.         private static Expression GetExpression(ParameterExpression param, Filter filter)  
    20.         {  
    21.             MemberExpression member = Expression.Property(param, filter.PropertyName);  
    22.             Expression handledMember = member;  
    23.             ConstantExpression constant = Expression.Constant(filter.Value);  
    24.   
    25.             if (member.Member.MemberType == MemberTypes.Property)  
    26.             {  
    27.                 Type propertyType = ((PropertyInfo)member.Member).PropertyType;  
    28.                 if (propertyType == typeof(string))  
    29.                 {  
    30.                     handledMember = Expression.Call(member, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));  
    31.                 }  
    32.                 if (propertyType == typeof(DateTime?))  
    33.                 {  
    34.                     handledMember = Expression.Property(member, typeof(DateTime?).GetProperty("Value"));  
    35.                 }  
    36.             }  
    37.   
    38.             switch (filter.Operation)  
    39.             {  
    40.                 case Op.Equals:  
    41.                     return Expression.Equal(handledMember, constant);  
    42.                 case Op.GreaterThan:  
    43.                     return Expression.GreaterThan(handledMember, constant);  
    44.                 case Op.GreaterThanOrEqual:  
    45.                     return Expression.GreaterThanOrEqual(handledMember, constant);  
    46.                 case Op.LessThan:  
    47.                     return Expression.LessThan(handledMember, constant);  
    48.                 case Op.LessThanOrEqual:  
    49.                     return Expression.LessThanOrEqual(handledMember, constant);  
    50.                 case Op.Contains:  
    51.                     return Expression.Call(handledMember, containsMethod, constant);  
    52.                 case Op.StartsWith:  
    53.                     return Expression.Call(handledMember, startsWithMethod, constant);  
    54.                 case Op.EndsWith:  
    55.                     return Expression.Call(handledMember, endsWithMethod, constant);  
    56.             }  
    57.   
    58.             return null;  
    59.         }  
    60.         private static BinaryExpression GetORExpression(ParameterExpression param, Filter filter1, Filter filter2)  
    61.         {  
    62.             Expression bin1 = GetExpression(param, filter1);  
    63.             Expression bin2 = GetExpression(param, filter2);  
    64.   
    65.             return Expression.Or(bin1, bin2);  
    66.         }  
    67.   
    68.         private static Expression GetExpression(ParameterExpression param, IList<Filter> orFilters)  
    69.         {  
    70.             if (orFilters.Count == 0)  
    71.                 return null;  
    72.   
    73.             Expression exp = null;  
    74.   
    75.             if (orFilters.Count == 1)  
    76.             {  
    77.                 exp = GetExpression(param, orFilters[0]);  
    78.             }  
    79.             else if (orFilters.Count == 2)  
    80.             {  
    81.                 exp = GetORExpression(param, orFilters[0], orFilters[1]);  
    82.             }  
    83.             else  
    84.             {  
    85.                 while (orFilters.Count > 0)  
    86.                 {  
    87.                     var f1 = orFilters[0];  
    88.                     var f2 = orFilters[1];  
    89.   
    90.                     if (exp == null)  
    91.                     {  
    92.                         exp = GetORExpression(param, orFilters[0], orFilters[1]);  
    93.                     }  
    94.                     else  
    95.                     {  
    96.                         exp = Expression.Or(exp, GetORExpression(param, orFilters[0], orFilters[1]));  
    97.                     }  
    98.                     orFilters.Remove(f1);  
    99.                     orFilters.Remove(f2);  
    100.   
    101.                     if (orFilters.Count == 1)  
    102.                     {  
    103.                         exp = Expression.Or(exp, GetExpression(param, orFilters[0]));  
    104.                         orFilters.RemoveAt(0);  
    105.                     }  
    106.                 }  
    107.             }  
    108.   
    109.             return exp;  
    110.         }  
    111.   
    112.         public static Expression<Func<T, bool>> GetExpression<T>(FilterCollection filters)  
    113.         {  
    114.             if (filters == null || filters.Count == 0)  
    115.                 return null;  
    116.   
    117.             ParameterExpression param = Expression.Parameter(typeof(T), "t");  
    118.             Expression exp = null;  
    119.   
    120.             if (filters.Count == 1)  
    121.             {  
    122.                 exp = GetExpression(param, filters[0]);  
    123.             }  
    124.             else if (filters.Count == 2)  
    125.             {  
    126.                 exp = Expression.AndAlso(GetExpression(param, filters[0]), GetExpression(param, filters[1]));  
    127.             }  
    128.   
    129.             else  
    130.             {  
    131.                 while (filters.Count > 0)  
    132.                 {  
    133.                     var f1 = filters[0];  
    134.                     var f2 = filters[1];  
    135.                     var f1Andf2 = Expression.AndAlso(GetExpression(param, filters[0]), GetExpression(param, filters[1]));  
    136.                     if (exp == null)  
    137.                     {  
    138.                         exp = f1Andf2;  
    139.                     }  
    140.                     else  
    141.                     {  
    142.                         exp = Expression.AndAlso(exp, f1Andf2);  
    143.                     }  
    144.   
    145.                     filters.Remove(f1);  
    146.                     filters.Remove(f2);  
    147.   
    148.                     if (filters.Count == 1)  
    149.                     {  
    150.                         exp = Expression.AndAlso(exp, GetExpression(param, filters[0]));  
    151.                         filters.RemoveAt(0);  
    152.                     }  
    153.                 }  
    154.             }  
    155.   
    156.             return Expression.Lambda<Func<T, bool>>(exp, param);  
    157.         }  
    158.     }  
    159. }  


    再来一个OrderBy动态构建

    [csharp] view plain copy
     
    1. using System;  
    2. using System.Collections.Generic;  
    3. using System.Linq;  
    4. using System.Linq.Expressions;  
    5. using System.Reflection;  
    6. using System.Text;  
    7.   
    8. namespace Jurassic.Sooil.Com  
    9. {  
    10.     public static class OrderExpression  
    11.     {  
    12.         public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)  
    13.         {  
    14.             return ApplyOrder<T>(source, property, "OrderBy");  
    15.         }  
    16.         public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)  
    17.         {  
    18.             return ApplyOrder<T>(source, property, "OrderByDescending");  
    19.         }  
    20.         public static IOrderedQueryable<T> ThenBy<T>(this IOrderedQueryable<T> source, string property)  
    21.         {  
    22.             return ApplyOrder<T>(source, property, "ThenBy");  
    23.         }  
    24.         public static IOrderedQueryable<T> ThenByDescending<T>(this IOrderedQueryable<T> source, string property)  
    25.         {  
    26.             return ApplyOrder<T>(source, property, "ThenByDescending");  
    27.         }  
    28.         static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)  
    29.         {  
    30.             string[] props = property.Split('.');  
    31.             Type type = typeof(T);  
    32.             ParameterExpression arg = Expression.Parameter(type, "x");  
    33.             Expression expr = arg;  
    34.             foreach (string prop in props)  
    35.             {  
    36.                 // use reflection (not ComponentModel) to mirror LINQ  
    37.                 PropertyInfo pi = type.GetProperty(prop);  
    38.                 expr = Expression.Property(expr, pi);  
    39.                 type = pi.PropertyType;  
    40.             }  
    41.             Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);  
    42.             LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);  
    43.   
    44.             object result = typeof(Queryable).GetMethods().Single(  
    45.                     method => method.Name == methodName  
    46.                             && method.IsGenericMethodDefinition  
    47.                             && method.GetGenericArguments().Length == 2  
    48.                             && method.GetParameters().Length == 2)  
    49.                     .MakeGenericMethod(typeof(T), type)  
    50.                     .Invoke(null, new object[] { source, lambda });  
    51.             return (IOrderedQueryable<T>)result;  
    52.         }   
    53.     }  
    54. }  


    至此动态构建LINQ查询结束!花了上班时间一上午,还是相当值得的,不过被项目经理知道了得哭死!

    不管如何,学到手的才是自己的!

  • 相关阅读:
    Unity3d-UI插件EZGUI官方视频教程
    安装安卓模拟器和unity3d插件EZGUI
    NGUI的原理机制:深入剖析UIPanel,UIWidget,UIDrawCall底层原理
    分享我的2014年3月unity3d面试题与参考答案
    WP8持续集成之通过命令行跑单元测试
    深入学习HttpClient(一)扩展额外的功能
    Windows Phone实用教程:利用Blend为程序添加设计时数据
    WP架构设计(一)MVVM回顾
    Windows Phone Unit Test 环境搭建
    Caliburn Micro框架快速上手(WP)
  • 原文地址:https://www.cnblogs.com/sjqq/p/8428775.html
Copyright © 2011-2022 走看看