c#——表达式树在LINQ动态查询
一般如果逻辑比较简单,只是存在有的情况多一个查询条件,有的情况不需要添加该查询条件
简单方式这样操作就可以了
- 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查询结束!花了上班时间一上午,还是相当值得的,不过被项目经理知道了得哭死!
不管如何,学到手的才是自己的!
c#——表达式树在LINQ动态查询的更多相关文章
- 表达式树在LINQ动态查询
动态构建表达式树,最佳实践版,很实用! public class FilterCollection : Collection<IList<Filter>> { public F ...
- Linq动态查询与模糊查询 ---转
Linq动态查询与模糊查询(带源码示例) 继LINQ动态组合查询PredicateExtensions讲解 ----- 在用上面的方法时遇到了些问题 解决 LINQ to Entities 不支持 L ...
- Linq动态查询简易解决之道(原创)
因为项目需要使用Linq来查询数据,但是在多条件查询时,需要使用一大堆if(...!=string.empty)等判断条件感觉不是很优雅.网上搜索以下,大概找到了两种办法,一种是老外写的一个类,感觉用 ...
- Linq 动态查询排序
Linq的排序一般是这样写的: query.OrderBy(x => x.Tel).Skip().Take(); 实际使用中排序字段可能是通过字符类型的参数来设置的,于是想这样实现: query ...
- 洛谷3834 hdu2665主席树模板,动态查询区间第k小
题目链接:https://www.luogu.com.cn/problem/P3834 对于区间查询第k小的问题,在区间数量达到5e5的时候是难以用朴素数据结构实现的,这时候主席树就应运而生了,主席树 ...
- Linq动态查询
public class ExpressionCall { List<Customer> customers = new List<Customer>() { new Cust ...
- linq字符串搜索条件,排序条件-linq动态查询语句 Dynamic LINQ
在做搜索和排序的时候,往往是前台传过来的字符串做条件,参数的数量还不定,这就需要用拼sql语句一样拼linq语句.而linq语句又是强类型的,不能用字符串拼出来. 现在好了,有个开源的linq扩展方法 ...
- LINQ动态查询类--[DynamicLinqExpressions]
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.L ...
- 转载:C#特性-表达式树
原文地址:http://www.cnblogs.com/tianfan/ 表达式树基础 刚接触LINQ的人往往觉得表达式树很不容易理解.通过这篇文章我希望大家看到它其实并不像想象中那么难.您只要有普通 ...
随机推荐
- Unity3d 显示IOS基本的游戏中心脚本
using UnityEngine; using UnityEngine.SocialPlatforms; public class Startup : MonoBehaviour { // we'l ...
- 算法笔记_103:蓝桥杯练习 算法提高 金明的预算方案(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些 ...
- mysql 取字段内容的第一个字符并大写
update words set `indexkey` = UPPER(left(word,1)) mysql 取字段内容的第一个字符并大写 用到两个mysql函数: 转换为大写:upper( ) 截 ...
- android 从Activity 获取 rootView 根节点
private static View getRootView(Activity context) { return ((ViewGroup)context.findViewById(android. ...
- 排序(2)---------简单插入排序(C语言实现)
插入排序(Insertion Sort)的算法描写叙述是一种简单直观的排序算法. 它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到对应位置并插入.插入排序在实现上,通常 ...
- 基于Qt的A*算法可视化分析
代码地址如下:http://www.demodashi.com/demo/13677.html 需求 之前做过一个无人车需要自主寻找最佳路径,所以研究了相关的寻路算法,最终选择A算法,因为其简单易懂, ...
- Qt for Android 开发大坑
Qt for Android 开发大坑 作者: qyvlik Qt 5.5.1 这里说一说比較常见的 Qt 开发安卓的大坑. 希望同学们不要做无谓的挣扎,跳过这些坑. 输入框 首当其冲的是输入框,Qt ...
- 【转】火星坐标、百度坐标、WGS-84坐标相互转换及墨卡托投影坐标转经纬度JavaScript版
原文地址:https://www.cnblogs.com/fwc1994/p/5884115.html 火星坐标 火星坐标是国家测绘局为了国家安全在原始坐标的基础上进行偏移得到的坐标,基本国内的电子地 ...
- mybatis开发流程,增删改查
一.开发流程 1)引jar包 //mybatis_core mybatis3.4core\asm-5.2.jar mybatis3.4core\cglib-.jar mybatis3.4core\co ...
- 计算机系统监控 PerformanceCounter
PerformanceCounter 컴퓨터 성능 머니터링 CUP Processor 메모리 하터웨어 DB (CPU,User Connection,Batch Request,Blocking ...