• 动态拼接表达式树


    问题来源于我正在做的日志功能模块:界面如下

    界面上的查询条件,根据用户的操作会有不同的状态

    比如:用户名称这个文本框有值的话就作为查询条件,没有的话就不作为查询条件,一个查询条件还好;现在有七八个条件的动态组合

    原来有一个条件的时候都是这样写的:

    Expression<Func<Log, bool>> a = e => e.UserName.Contains("李行周");

    Expression<Func<Log, bool>> a = e => e.UserName.Contains("李行周")&&e.CreateDateTime<="2018年1月10日 13:57:18";

    当有多个条件的时候,每次都要把语句重新写就有问题,出现了重复

    我记得之前用rafy的时候,rafy是在内部实现了

    internal class EntityQueryable<TEntity> : IOrderedQueryable<TEntity>
    

      用的时候就创建 一个可查询的接口对象

     var q = this.CreateLinqQuery<External>();
                q = q.Where(e => e.TransactionExternalId == transactionExternalId);
                return (ExternalList)this.QueryData(q);
    

      

    但现在我要查的是Mongodb没有用rafy,在网上找了一些说是用动态表达式拼接 主要参考的地址是:https://www.cnblogs.com/wzxinchen/p/4611592.html

    我的实现,一些代码直接用的转载博客的

    public class SqlFilter
        {
            public static SqlFilter Create(string propertyName, Operation operation, object value)
            {
                return new SqlFilter()
                {
                    Name = propertyName,
                    Operation = operation,
                    Value = value
                };
            }
    
            /// <summary>
            /// 字段名
            /// </summary>
            public string Name { get; set; }
    
            /// <summary>
            /// 搜索操作,大于小于等于
            /// </summary>
            public Operation Operation { get; set; }
    
            /// <summary>
            /// 搜索参数值
            /// </summary>
            public object Value { get; set; }
        }
     public enum Operation
        {
            GreaterThan,
            LessThan,
            GreaterThanOrEqual,
            LessThanOrEqual,
            NotEqual,
            Equal,
            Like,
            In
        }
    public class ExpressionBuilder<T> where T : class
        {
    
            public ExpressionBuilder()
            {
    
            }
    
            /// <summary>
            /// 生成表达式
            /// </summary>
            /// <param name="filters">要拼接的条件</param>
            /// <param name="filterNameMap">字段映射集合</param>
            /// <returns></returns>
            public Expression<Func<T, bool>> Build(IList<SqlFilter> filters, Dictionary<string, string> filterNameMap)
            {
                var parameterExp = Expression.Parameter(typeof(T), "x");
    
                Expression twoBinaryExpressionMerge = null;
    
                for (int i = 0; i < filters.Count; i++)
                {
                    var sqlFilter = filters[i];
    
                    if (i == 0)
                    {
                        twoBinaryExpressionMerge = this.CreateBinaryExpression(sqlFilter, parameterExp);
                    }
                    else
                    {
                        var rightBinaryExpression = this.CreateBinaryExpression(sqlFilter, parameterExp);
    
                        twoBinaryExpressionMerge = Expression.And(twoBinaryExpressionMerge, rightBinaryExpression);
                    }
                }
    
                //结果是:x=>x.Id==1,这个··还需要解释么,很简单,不是么。创建一个相等的表达式,然后传入左边和右边的表达式
                //当然到这儿还不能用,还需要继续
                var lambda = Expression.Lambda<Func<T, bool>>(twoBinaryExpressionMerge, parameterExp);
    
                return lambda;
            }
    
            public Expression CreateBinaryExpression(SqlFilter sqlFilter, ParameterExpression parameterExpression)
            {
                Expression binaryExpression = null;
                //结果是这样:x=>,x是变量名
                var propertyExp = Expression.Property(parameterExpression, sqlFilter.Name);
                //结果是这样:x=>x.Id,这句是为了构建访问属性的表达式
                //上面这句第一个参数是你要取属性的对象表达式。我们要拼的表达式是x=>x.Id==1,==1这块先不管,其实就是x=>x.Id,那么其实我们就是对x进行取属性值,而x是parameterExp,所以第一个参数是parameterExp,第二个参数好说,就是属性名
                var constExp = Expression.Constant(sqlFilter.Value, sqlFilter.Value.GetType());
                var method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
                switch (sqlFilter.Operation)
                {
                    case Operation.GreaterThan:
                        binaryExpression = Expression.GreaterThan(propertyExp, constExp);
                        break;
                    case Operation.LessThan:
                        binaryExpression = Expression.LessThan(propertyExp, constExp);
                        break;
                    case Operation.GreaterThanOrEqual:
                        binaryExpression = Expression.GreaterThanOrEqual(propertyExp, constExp);
                        break;
                    case Operation.LessThanOrEqual:
                        binaryExpression = Expression.LessThanOrEqual(propertyExp, constExp);
                        break;
                    case Operation.NotEqual:
                        binaryExpression = Expression.NotEqual(propertyExp, constExp);
                        break;
                    case Operation.Equal:
                        binaryExpression = Expression.Equal(propertyExp, constExp);
                        break;
                    case Operation.Like:
                        constExp = Expression.Constant(sqlFilter.Value, typeof(string));
                        binaryExpression = Expression.Call(propertyExp, method, constExp);
                        break;
                    case Operation.In:
                        binaryExpression = null;
                        break;
                    default:
                        binaryExpression = null;
                        break;
                }
                return binaryExpression;
            }
        }

    用法如下:

     var builder = new ExpressionBuilder<Log>();//实例化组件,User是什么下面说
                    var filters = new List<SqlFilter>();
    
                    if (!string.IsNullOrWhiteSpace(queryLogPar.UserName))
                        filters.Add(SqlFilter.Create("Username", Operation.Like, queryLogPar.UserName));
                    if (queryLogPar.StartDate != null)
                        filters.Add(SqlFilter.Create("CreateDateTime", Operation.GreaterThanOrEqual, queryLogPar.StartDate));
                    if (queryLogPar.EndDate != null)
                        filters.Add(SqlFilter.Create("CreateDateTime", Operation.LessThanOrEqual, queryLogPar.EndDate));
                    if (!string.IsNullOrWhiteSpace(queryLogPar.Exception))
                        filters.Add(SqlFilter.Create("Exception", Operation.Like, queryLogPar.Exception));
    
                    if (!string.IsNullOrWhiteSpace(queryLogPar.TenantId))
                        filters.Add(SqlFilter.Create("TenantId", Operation.Like, queryLogPar.TenantId));
    
                    if (!string.IsNullOrWhiteSpace(queryLogPar.RawUrl))
                        filters.Add(SqlFilter.Create("RawUrl", Operation.Like, queryLogPar.RawUrl));
    
                    if (!string.IsNullOrWhiteSpace(queryLogPar.ExtTenantId))
                        filters.Add(SqlFilter.Create("ExtTenantId", Operation.Like, queryLogPar.ExtTenantId));
    
                    if (queryLogPar.LogLevel != -1)
                        filters.Add(SqlFilter.Create("LogLevel", Operation.Equal, (LogLevel)queryLogPar.LogLevel));
    
                    if (queryLogPar.LogType != -1)
                        filters.Add(SqlFilter.Create("LogType", Operation.Equal, (LogType)queryLogPar.LogType));
    
                    var where = builder.Build(filters, new Dictionary<string, string>());//根据上面的条件,拼接出表达式树
                    return where;
  • 相关阅读:
    数组中,奇数放前偶数放后
    回溯法
    java+selenium的helloworld
    我为什么反对纯算法面试题
    算法面试题
    关于算法
    伴随开发人员成长的问题:工程重要,还是算法重要?细节重要,还是架构重要?
    数据结构和算法为什么这么重要?
    JSP网站开发基础总结《三》
    JSP网站开发基础总结《二》
  • 原文地址:https://www.cnblogs.com/gdnyfcuso/p/8258467.html
Copyright © 2020-2023  润新知