.net core 实例教程(四)Ef Core实现动态查询及排序条件拼接
本文源码下载地址:http://www.80cxy.com/Blog/ResourceView?arId=202403191532545995NAAqJh
系列教程地址:http://www.80cxy.com/Blog/ArticleView?arId=202403191517574161ay3s5V
本文实现动态查询拼接功能,前台传入查询条件参数格式如下:
wheres: '[{\"name\":\"Name\",\"value\":\"11\",\"option\":\"EQ\"},{\"name\":\"IdCard\",\"value\":\"22\",\"option\":\"EQ\"}]',
name为查询字段名,value为查询值,option为查询条件。
前台传入排序条件参数为:字符串sort:排序字段, 字符串order:排序方式。
后台接收到查询条件参数后先转换为List,然后通过DataFilterConvertor类构造Lambda表达式树构造查询条件。
将排序字段转换为Dictionary,让后通过DataOrderConvertor类构造Lambda表达式树构造排序条件
一、相关代码如下:
using SignUp.Common.Enum; using SignUp.Common.Extensions; namespace SignUp.Common.DataFilter { /// <summary> /// 参数转换 /// </summary> public static class FormatParameters { public static List<DataFilter> GetSearchParameters(string wheres) { List<DataFilter> searchParametersList = new List<DataFilter>(); if (!string.IsNullOrEmpty(wheres)) { try { searchParametersList = wheres.DeserializeObject<List<DataFilter>>(); } catch { } } return searchParametersList; } public static Dictionary<string, QueryOrderBy> GetOrderParameters(string sort, string order) { Dictionary<string, QueryOrderBy> orderBy = new Dictionary<string, QueryOrderBy>(); if (order.ToLower() == "desc") orderBy.Add(sort, QueryOrderBy.Desc); else orderBy.Add(sort, QueryOrderBy.Asc); return orderBy; } } } using SignUp.Common.Enum; using System.Linq.Expressions; namespace SignUp.Common.DataFilter { /// <summary> /// 前端查询条件转换为Expression供EFCore使用 /// </summary> /// <typeparam name="T"></typeparam> public static class DataFilterConvertor<T> where T : class { #region 查询条件 /// <summary> /// 入口方法,把数据过滤器转换为Expression /// </summary> /// <param name="dataFilterList"></param> /// <returns></returns> public static Expression<Func<T, bool>> ToExpression(List<DataFilter> dataFilterList) { if (dataFilterList == null || dataFilterList.Count < 1) { return (T) => true; } ParameterExpression parameterExpression = Expression.Parameter(typeof(T)); Expression firstLambdaExpression = GetSingleFilterExpression(parameterExpression, dataFilterList[0]); Expression binaryExpression = Expression.AndAlso(Expression.Constant(true), firstLambdaExpression); foreach (DataFilter dataFilter in dataFilterList.Skip(1)) { Expression lambdaExpression = GetSingleFilterExpression(parameterExpression, dataFilter); binaryExpression = Expression.AndAlso(binaryExpression, lambdaExpression); } return Expression.Lambda<Func<T, bool>>(binaryExpression, parameterExpression); } /// <summary> /// 获取单个过滤条件的Expression /// </summary> /// <param name="parameterExpression"></param> /// <param name="dataFilter"></param> /// <returns></returns> private static Expression GetSingleFilterExpression(ParameterExpression parameterExpression, DataFilter dataFilter) { MemberExpression? memberExpression = null; if (dataFilter.Name.Contains('.')) { string[] multiLevelProperties = dataFilter.Name.Split('.'); memberExpression = Expression.Property(parameterExpression, multiLevelProperties[0].ToString()); foreach (string propertyName in multiLevelProperties.Skip(1)) { memberExpression = Expression.Property(memberExpression, propertyName); } } else { memberExpression = Expression.Property(parameterExpression, dataFilter.Name); } ConstantExpression? constantExpression = null; if (!string.IsNullOrEmpty(dataFilter.Value)) { string fieldsType = ""; if (memberExpression.Type.FullName.IndexOf("DateTime") != -1) fieldsType = "DateTime"; else if (memberExpression.Type.FullName.IndexOf("System.Guid") != -1) fieldsType = "Guid"; else fieldsType = memberExpression.Type.Name; dynamic formatedValue = DataValueFormat(dataFilter.Value, fieldsType); constantExpression = Expression.Constant(formatedValue, memberExpression.Type); } else { constantExpression = Expression.Constant(dataFilter.ValueList, GetGenericListType(memberExpression.Type.Name)); if (memberExpression.Type.Name == "String") { constantExpression = Expression.Constant(dataFilter.ValueList, typeof(List<string>)); } else { constantExpression = Expression.Constant(dataFilter.ValueList, typeof(List<int>)); } } Expression body = CreateExpressionBody(memberExpression, constantExpression, dataFilter.Option); return body; } /// <summary> /// 根据字段,比较值获取Expression /// </summary> /// <param name="memberExpression"></param> /// <param name="constantExpression"></param> /// <param name="operatorStr"></param> /// <returns></returns> /// <exception cref="ArgumentException"></exception> private static Expression CreateExpressionBody( MemberExpression memberExpression, ConstantExpression constantExpression, string operatorStr) { if (!System.Enum.TryParse($"OPT_{operatorStr}".ToUpper(), true, out OperatorEnum operatorEnum)) { throw new ArgumentException($"不支持操作符:{operatorStr}"); } Type? genericListType = null; switch (operatorEnum) { case OperatorEnum.OPT_EQ: return Expression.Equal(memberExpression, constantExpression); case OperatorEnum.OPT_NQ: return Expression.NotEqual(memberExpression, constantExpression); case OperatorEnum.OPT_LIKE: return Expression.Call(memberExpression, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), constantExpression); case OperatorEnum.OPT_NOTLIKE: return Expression.Not(Expression.Call(memberExpression, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), constantExpression)); case OperatorEnum.OPT_GT: case OperatorEnum.OPT_GE: case OperatorEnum.OPT_LT: case OperatorEnum.OPT_LE: return GetCompareExpression(memberExpression, constantExpression, operatorEnum); case OperatorEnum.OPT_IN: genericListType = GetGenericListType(memberExpression.Type.Name); return Expression.Call(constantExpression, genericListType.GetMethod("Contains", new Type[] { memberExpression.Type }), memberExpression); case OperatorEnum.OPT_NOTIN: genericListType = GetGenericListType(memberExpression.Type.Name); return Expression.Not(Expression.Call(constantExpression, genericListType.GetMethod("Contains", new Type[] { memberExpression.Type }), memberExpression)); default: throw new ArgumentException($"不支持操作符:{operatorEnum}"); } } /// <summary> /// 获取比较表达式,支持字符串、数字、日期比较大小 /// </summary> /// <param name="memberExpression"></param> /// <param name="constantExpression"></param> /// <param name="operatorEnum"></param> /// <returns></returns> private static Expression GetCompareExpression(MemberExpression memberExpression, ConstantExpression constantExpression, OperatorEnum operatorEnum) { ConstantExpression constant0Expression = Expression.Constant(0); Expression strCompareExpression = null; if (memberExpression.Type.Name == BasicDataType.String.ToString()) { strCompareExpression = Expression.Call(memberExpression, typeof(string).GetMethod("CompareTo", new Type[] { typeof(string) }), constantExpression); } switch (operatorEnum) { case OperatorEnum.OPT_GT: if (memberExpression.Type.Name == BasicDataType.String.ToString()) { return Expression.GreaterThan(strCompareExpression, constant0Expression); } else { return Expression.GreaterThan(memberExpression, constantExpression); } case OperatorEnum.OPT_GE: if (memberExpression.Type.Name == BasicDataType.String.ToString()) { return Expression.GreaterThanOrEqual(strCompareExpression, constant0Expression); } else { return Expression.GreaterThanOrEqual(memberExpression, constantExpression); } case OperatorEnum.OPT_LT: if (memberExpression.Type.Name == BasicDataType.String.ToString()) { return Expression.LessThan(strCompareExpression, constant0Expression); } else { return Expression.LessThan(memberExpression, constantExpression); } case OperatorEnum.OPT_LE: if (memberExpression.Type.Name == BasicDataType.String.ToString()) { return Expression.LessThanOrEqual(strCompareExpression, constant0Expression); } else { return Expression.LessThanOrEqual(memberExpression, constantExpression); } default: return null; } } /// <summary> /// 根据属性类型对获取list泛型类型 /// </summary> /// <param name="typeName"></param> /// <returns></returns> /// <exception cref="ArgumentException"></exception> private static Type GetGenericListType(string typeName) { if (!System.Enum.TryParse(typeName, true, out BasicDataType dataType)) { throw new ArgumentException($"不支的数据类型:{typeName}"); } switch (dataType) { case BasicDataType.String: return typeof(List<string>); case BasicDataType.Int32: return typeof(List<string>); default: throw new ArgumentException("不支持的泛型类型转换"); } } /// <summary> /// 输入value值根据对应的属性类型格式化 /// </summary> /// <param name="value"></param> /// <param name="typeName"></param> /// <returns></returns> /// <exception cref="ArgumentException"></exception> /// <exception cref="Exception"></exception> private static dynamic DataValueFormat(string value, string typeName) { if (!System.Enum.TryParse(typeName, true, out BasicDataType dataType)) { throw new ArgumentException($"不支的数据类型:{typeName}"); } switch (dataType) { case BasicDataType.Int32: return Convert.ToInt32(value); case BasicDataType.Int64: return Convert.ToInt64(value); case BasicDataType.Single: return Convert.ToSingle(value); case BasicDataType.Double: return Convert.ToDouble(value); case BasicDataType.Decimal: return Convert.ToDecimal(value); case BasicDataType.String: return value; case BasicDataType.DateTime: return Convert.ToDateTime(value); case BasicDataType.Guid: return Guid.Parse(value); case BasicDataType.Boolean: value = value.ToUpper(); if (value == "TRUE" || value == "1") { return true; } else if (value == "FALSE" || value == "0") { return false; } else { throw new Exception($"{value}不能被解析为Bool类型"); } default: throw new Exception($"{value}不能被解析为{typeName}类型"); } } #endregion } } using SignUp.Common.Enum; using System.Linq.Expressions; namespace SignUp.Common.DataFilter { /// <summary> /// 动态实现排序 /// </summary> public static class DataOrderConvertor { /// <summary> /// 创建lambda表达式:p=>true /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public static Expression<Func<T, bool>> True<T>() { return p => true; } /// <summary> /// 创建lambda表达式:p=>false /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public static Expression<Func<T, bool>> False<T>() { return p => false; } public static ParameterExpression GetExpressionParameter(this Type type) { return Expression.Parameter(type, "p"); } /// <summary> /// 创建lambda表达式:p=>p.propertyName /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="TKey"></typeparam> /// <param name="sort"></param> /// <returns></returns> public static Expression<Func<T, TKey>> GetExpression<T, TKey>(this string propertyName) { return propertyName.GetExpression<T, TKey>(typeof(T).GetExpressionParameter()); } /// <summary> /// 创建委托有返回值的表达式:p=>p.propertyName /// </summary> /// <typeparam name="T"></typeparam> /// <typeparam name="TKey"></typeparam> /// <param name="sort"></param> /// <returns></returns> public static Func<T, TKey> GetFun<T, TKey>(this string propertyName) { return propertyName.GetExpression<T, TKey>(typeof(T).GetExpressionParameter()).Compile(); } /// <summary> /// 创建lambda表达式:p=>false /// 在已知TKey字段类型时,如动态排序OrderBy(x=>x.ID)会用到此功能,返回的就是x=>x.ID /// Expression<Func<Out_Scheduling, DateTime>> expression = x => x.CreateDate;指定了类型 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public static Expression<Func<T, TKey>> GetExpression<T, TKey>(this string propertyName, ParameterExpression parameter) { if (typeof(TKey).Name == "Object") return Expression.Lambda<Func<T, TKey>>(Expression.Convert(Expression.Property(parameter, propertyName), typeof(object)), parameter); return Expression.Lambda<Func<T, TKey>>(Expression.Property(parameter, propertyName), parameter); } /// <summary> /// 创建lambda表达式:p=>false /// object不能确认字段类型(datetime,int,string),如动态排序OrderBy(x=>x.ID)会用到此功能,返回的就是x=>x.ID /// Expression<Func<Out_Scheduling, object>> expression = x => x.CreateDate;任意类型的字段 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public static Expression<Func<T, object>> GetExpression<T>(this string propertyName) { return propertyName.GetExpression<T, object>(typeof(T).GetExpressionParameter()); } public static Expression<Func<T, object>> GetExpression<T>(this string propertyName, ParameterExpression parameter) { return Expression.Lambda<Func<T, object>>(Expression.Convert(Expression.Property(parameter, propertyName), typeof(object)), parameter); } /// <summary> /// 解析多字段排序 /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="queryable"></param> /// <param name="orderBySelector">string=排序的字段,bool=true降序/false升序</param> /// <returns></returns> public static IQueryable<TEntity> OrderConditions<TEntity>(this IQueryable<TEntity> queryable, Dictionary<string, QueryOrderBy> orderBySelector) { string[] orderByKeys = orderBySelector.Select(x => x.Key).ToArray(); if (orderByKeys == null || orderByKeys.Length == 0) return queryable; IOrderedQueryable<TEntity> queryableOrderBy = null; // string orderByKey = orderByKeys[^1]; string orderByKey = orderByKeys[orderByKeys.Length - 1]; queryableOrderBy = orderBySelector[orderByKey] == QueryOrderBy.Desc ? queryableOrderBy = queryable.OrderByDescending(orderByKey.GetExpression<TEntity>()) : queryable.OrderBy(orderByKey.GetExpression<TEntity>()); for (int i = orderByKeys.Length - 2; i >= 0; i--) { queryableOrderBy = orderBySelector[orderByKeys[i]] == QueryOrderBy.Desc ? queryableOrderBy.ThenByDescending(orderByKeys[i].GetExpression<TEntity>()) : queryableOrderBy.ThenBy(orderByKeys[i].GetExpression<TEntity>()); } return queryableOrderBy; } } } namespace SignUp.Common.DataFilter { /// <summary> /// FE CORE动态查询条件拼接,接收前台查询条件 /// </summary> public class DataFilter { public string Name { get; set; } public string Option { get; set; } public string Value { get; set; } public List<string> ValueList { get; set; } } } namespace SignUp.Common.Enum { /// <summary> /// FE CORE动态查询条件拼接,支持的数据类型 /// </summary> public enum BasicDataType { Int32, Int64, Single, Double, Decimal, Boolean, String, DateTime, Guid } } namespace SignUp.Common.Enum { /// <summary> /// FE CORE动态查询条件拼接,支持的运算符 /// </summary> public enum OperatorEnum { // 等于 OPT_EQ, // 不等于 OPT_NQ, // 包含 OPT_LIKE, // 不包含 OPT_NOTLIKE, // 大于 OPT_GT, // 大于等于 OPT_GE, // 小于 OPT_LT, // 小于等于 OPT_LE, // 数组包含 OPT_IN, // 数组不包含 OPT_NOTIN, } } namespace SignUp.Common.Enum { /// <summary> /// 排序方式 /// </summary> public enum QueryOrderBy { Desc = 1, Asc = 2 } }
二、调用方法
public async Task<(SysUser[], int total)> GetUserList(int pageIndex, int pageSize, string wheres, string sort, string order) { //where查询条件 List<DataFilter> searchParametersList = FormatParameters.GetSearchParameters(wheres); //order排序条件 Dictionary<string, QueryOrderBy> orderBy = FormatParameters.GetOrderParameters(sort, order); //构造查询条件 Expression<Func<SysUser, bool>> expression = DataFilterConvertor<SysUser>.ToExpression(searchParametersList); var listAll = _dbContext.SysUser.Where(expression); int total = listAll.Count(); var list = await listAll.OrderConditions(orderBy).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToArrayAsync(); return (list, total); }
学习交流
附笔者学习 .net core开发时参考相关项目实例源码:asp.net core webapi项目实例源代码锦集下载(72个)
猜您可能还喜欢
- net core+webapi+nginx windows 服务器部署(1321)
- .Nuget Packages 太占C盘,删除后可以放到其他盘(1194)
- ASP.NET Core 配置 Swagger 显示接口注释描述信息(1094)
- vue调用接口后获取不到后端返回的Header响应头(964)
- .net core 系列实例开发教程-权限管理系统功能介绍(952)
- .net core 6.0 web API + SwaggerUI + IIS部署(912)
- .net core 实例教程(十二)配置启用Swagger中的【Authorize】按钮(831)
- .net core 实例教程(一)新建项目(797)
- .net core 实例教程(十四)配置 Swagger 显示接口注释描述信息及支持版本控制(783)
- .net 6中使用log4net写sqlserver数据库日志(756)
评论列表
发表评论
文章分类
文章归档
- 2025年3月 (1)
- 2024年6月 (2)
- 2024年5月 (2)
- 2024年4月 (4)
- 2024年3月 (30)
- 2024年1月 (4)
- 2023年12月 (2)
- 2023年11月 (4)
- 2023年10月 (4)
- 2023年9月 (6)
- 2023年3月 (2)
- 2023年2月 (1)
- 2023年1月 (1)
- 2022年12月 (1)
- 2022年9月 (21)
- 2022年8月 (10)
- 2022年7月 (3)
- 2022年4月 (1)
- 2022年3月 (13)
- 2021年8月 (1)
- 2021年3月 (1)
- 2020年12月 (42)
- 2020年11月 (7)
- 2020年10月 (5)
- 2020年8月 (1)
- 2020年6月 (1)
- 2020年3月 (2)
- 2019年12月 (8)
- 2019年11月 (3)
- 2019年9月 (1)
- 2019年4月 (1)
- 2019年3月 (6)
- 2019年2月 (1)
- 2018年7月 (7)
阅读排行
- 1.asp.net mvc内微信pc端、H5、JsApi支付方式总结(5702)
- 2.各大搜索网站网站收录提交入口地址(3201)
- 3.Windows 10休眠文件更改存储位置(3163)
- 4.ECharts仪表盘实例及参数使用详解(3095)
- 5.windows 10安装myeclipse 10破解补丁cracker.jar、run.bat闪退解决办法(2991)
- 6.HTML5 WebSocket与C#建立Socket连接实现代码(2866)
- 7.华为鸿蒙系统清除微信浏览器缓存方法(2779)
- 8.CERT_HAS_EXPIRED错误如何解决(2245)
- 9.Js异步async、await关键字详细介绍(lambda表达式中使用async和await关键字)(2188)
- 10.HBuilder编辑器格式化代码(2118)