美文网首页
.NET Core页面查询条件解析为Expression给EFC

.NET Core页面查询条件解析为Expression给EFC

作者: Messix_1102 | 来源:发表于2023-09-07 15:34 被阅读0次

定义接收参数的数据类型

public class DataFilter
{
    public string Name { get; set; }
    public string Option { get; set; }
    public string Value { get; set; }
    public List<string> ValueList { get; set; }
}

public enum BasicDataType
{
    Int32,
    Int64,
    Single,
    Double,
    Decimal,
    Boolean,
    String,
    DateTime
}

public enum OperatorEnum
{
    // 等于
    OPT_EQ,

    // 不等于
    OPT_NQ,

    // 包含
    OPT_LIKE,

    // 不包含
    OPT_NOTLIKE,

    // 大于
    OPT_GT,

    // 大于等于
    OPT_GE,

    // 小于
    OPT_LT,

    // 小于等于
    OPT_LE,

    // 数组包含
    OPT_IN,

    // 数组不包含
    OPT_NOTIN,
}

Expression 解析器

namespace XXX
{
    /// <summary>
    /// 前端过滤条件转换为Expression供EFCore使用
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public static class DataFilterConvertor<T> where T : class
    {
        /// <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))
            {
                dynamic formatedValue = DataValueFormat(dataFilter.Value, memberExpression.Type.Name);
                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 (!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 (!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 (!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.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}类型");
            }
        }
    }
}

调用

//...
Expression<Func<StructureModel, bool>> expression = 
    DataFilterConvertor<StructureModel>.ToExpression(requestVM.DataFilterList);
List<StructureModel> modelList = structureService.FindPageList(requestVM.PageIndex, 
    requestVM.PageSize, out totalCount, expression, "id", true).ToList();
//...

相关文章

  • vue3浏览器后退前进不刷新页面

    一、业务场景示例 页面A: 数据列表,有一些查询条件,如查询条件区域,查询结果为区域信息列表页面B: 数据详情,点...

  • 2018-08-03

    使用ASP.NET Core创建Razor页面Web应用 系统必备 1. .NET Core 2.1 SDK或更高...

  • CoreData+多线程

    基础知识:Core Data入门 查询语句:[IOS开发]CoreData条件查询之NSPredicate应用_超...

  • 后台涉及“管理”的几种主要功能及页面

    1、查询功能及页面 查询页面包含:“查询条件区域”、“查询结果区域”(包含结果表格、“结果数量统计”、“翻页功能(...

  • spring

    分为20个模块 core container core beans context expression lang...

  • .Net Core Api Swagger

    .Net Core Api 自动文档 环境: .net core 3.1建议 更换包源为国内地址 1 安装包 ...

  • 微服务架构性能问题排查

    A. 测试条件说明 创建服务:创建 asp.net core webapi 项目。 服务间接口调用:因为是.NET...

  • ABP 快速上手指南

    ABP文档 - 选择ASP.NET Core & Angular frameworks建立单页面应用SPA(Sin...

  • Spring AOP中pointcut expression表达

    Spring AOP中pointcut expression表达式解析 及匹配多个条件 任意公共方法的执行:exe...

  • find [options] path... [expressi

    在指定目录中,遍历搜索符合 expression 限定条件的文件、目录 options -P 不解析符号链接(默认...

网友评论

      本文标题:.NET Core页面查询条件解析为Expression给EFC

      本文链接:https://www.haomeiwen.com/subject/orxrvdtx.html