.net core 实例教程(四)Ef Core实现动态查询及排序条件拼接
小白浏览:6102024-03-15 15:42:21本文累计收益:0我也要赚钱

本文源码下载地址: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个)

评论列表
发表评论
+ 关注