当前位置:首页 > C#编程 > C#/.net框架 > 正文内容

c#——表达式树在LINQ动态查询

Jorge2年前 (2022-05-08)C#/.net框架824

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


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

C#
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查询条件,其实只是熟悉表达式树的其他提供的方法,非常简单。

C#
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

C#
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; }
    }}


再来看看查询结果:



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



接下来猛料哦


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


C#
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    }


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

C#
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动态构建

C#
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


扫描二维码推送至手机访问。

版权声明:本文由7点博客发布,如需转载请注明出处。

本文链接:http://6dot.cn/?id=52

标签: .NET.NET框架
分享给朋友:

“c#——表达式树在LINQ动态查询” 的相关文章

windows下c#程序提高实时性

windows下c#程序提高实时性

引言:我们手里的运控软件对实时性有了新要求。因为同设备上运行的其它视觉软件对cpu时间有变态的占用,压缩了运控软件的cpu占用时间。我们知道如果视觉软件卡一下,最多是处理时间长一点,但是运控软件卡一下,那就意味着撞机的问题,这个要严重得多。这个问题会持续把研究结果更新到本贴子。(一)提升线程和进程的...

C#中使用RegisterWindowMessage进行进程之间进行通讯

C#中使用RegisterWindowMessage进行进程之间进行通讯

注:大家都知道在window里,进程之间通讯可以用消息通讯。但是有个较冷门的知识就是RegisterWindowMessage。一般的sendmessage和postmessage是需要在窗体程序间进行通讯,你得知道对方窗口的句柄。这个句柄每次启动程序时是系统分配的,每次不一样。有了这个Regist...

索引器(C# 编程指南)

索引器(C# 编程指南)

 索引器允许类或结构的实例就像数组一样进行索引。 无需显式指定类型或实例成员,即可设置或检索索引值。 索引器类似于属性,不同之处在于它们的访问器需要使用参数。以下示例定义了一个泛型类,其中包含用于赋值和检索值的简单 get 和 set 访问器方法。&...

关于C#项目引用的一点经验

关于C#项目引用的一点经验

关于项目引用,有几种:(一)这种是引用系统的程序集(二)下面这种是引用你自己的项目“解决方案”(三)最后一种是浏览本机上的项目的dll。对于工程中有几十个项目的软件来说,虽然使用(二)是很方便。但是会编译速度奇慢,而且随着项目越多越慢。貌似他run之前都会把所有项目都试图更新一下。勇哥宿舍的电脑,实...

C# 异步和等待,async/await

C# 异步和等待,async/await

 首先,重点是:异步将从根本上改变大多数代码的编写方式。是的,我相信 async/await 会比 LINQ 产生更大的影响。理解异步将在短短几年内成为基本必需品。关键字介绍让我们直接开始吧。我将使用一些稍后将阐述的概念——请继续阅读第一部分。异步方法看起来像这样:public ...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。