.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个)
猜您可能还喜欢
- .Nuget Packages 太占C盘,删除后可以放到其他盘(1667)
- net core+webapi+nginx windows 服务器部署(1513)
- ASP.NET Core 配置 Swagger 显示接口注释描述信息(1281)
- .net core 6.0 web API + SwaggerUI + IIS部署(1269)
- vue调用接口后获取不到后端返回的Header响应头(1226)
- .net core 系列实例开发教程-权限管理系统功能介绍(1142)
- .net core 实例教程(十二)配置启用Swagger中的【Authorize】按钮(1116)
- .net core 实例教程(十一)生成JWT格式的token密码配置及代码(1035)
- .net core 实例教程(十四)配置 Swagger 显示接口注释描述信息及支持版本控制(998)
- .net core 实例教程(三)仓储及领域服务功能实现(既实现用户表的增删改查接口)(970)
评论列表
发表评论
文章分类
文章归档
- 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支付方式总结(5919)
- 2.Windows 10休眠文件更改存储位置(4000)
- 3.各大搜索网站网站收录提交入口地址(3504)
- 4.windows 10安装myeclipse 10破解补丁cracker.jar、run.bat闪退解决办法(3482)
- 5.ECharts仪表盘实例及参数使用详解(3463)
- 6.华为鸿蒙系统清除微信浏览器缓存方法(3256)
- 7.HTML5 WebSocket与C#建立Socket连接实现代码(3221)
- 8.CERT_HAS_EXPIRED错误如何解决(3021)
- 9.Js异步async、await关键字详细介绍(lambda表达式中使用async和await关键字)(2662)
- 10.HBuilder编辑器格式化代码(2430)
