zoukankan      html  css  js  c++  java
  • ORM开发之解析lambda实现完整查询(附测试例子)

    上次讲解了怎么解析匿名对象(ORM开发之解析lambda实现group查询),这次来实现解析二元运算,完成基本条件语法

    先看一个表达式

    query.Where(b => b.Number == 10&&b.Id<20);
    

    表达式结构

    一个运算符表示一个表达式,因此,此表达式实际上包含两个子表达式 b.Number==10 和b.Id<20 他们的关系为And

    看一个子表达式 b.Number==10
    按运算符为位置,左边为左操作数,右边为右操作数

    以And操作符来看,b.Number==10也为左操作数,b.Id<20为右操作数

    再增加其它条件时,也是同样的道理

    那么我们解析将一个子表达式 b.Number==10 转换为SQL逻辑,则需要:

    1. 取出左表达式对应的字段名称 Number
    2. 取出运算符 =
    3. 取出右表达式的值 10

    表达式类型

    由上可以看出,表达式分左边和右边,左右两边也可是子表达式,它们形成一个表达式树,基类型都为System.Linq.Expressions.Expression

    具体类型大致按下面划分为:

    1. BinaryExpression 表示包含二元运算符的表达式。 可以理解为一个子表达式,如 b.Number>10
    2. MemberExpression 表示访问字段或属性。 如 b.Number
    3. NewArrayExpression 表示创建新数组并可能初始化该新数组的元素。
    4. MethodCallExpression 表示对静态方法或实例方法的调用 如 b.Name.Contains("123")
    5. ConstantExpression 表示具有常量值的表达式 如 b.Name="hubro" 
    6. UnaryExpression 表示包含一元运算符的表达式

    因此,需要根据不同的类型解析不同的表达式

    开始解析

    拆分表达式树

    /// <summary>
            /// 拆分表达式树
            /// </summary>
            /// <param name="left"></param>
            /// <param name="right"></param>
            /// <param name="type"></param>
            /// <returns></returns>
            public string BinaryExpressionHandler(Expression left, Expression right, ExpressionType type)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("(");
                string needParKey = "=,>,<,>=,<=,<>";
                string leftPar = RouteExpressionHandler(left);//获取左边
                string typeStr = ExpressionTypeCast(type);//转换运算符
                var isRight = needParKey.IndexOf(typeStr) > -1;//用以区分是解析左边的名称还是右边的值
                string rightPar = RouteExpressionHandler(right, isRight);//获取右边
    
                string appendLeft = leftPar;
    
                sb.Append(appendLeft);//字段名称
               
                if (rightPar.ToUpper() == "NULL")
                {
                    if (typeStr == "=")
                        rightPar = " IS NULL ";
                    else if (typeStr == "<>")
                        rightPar = " IS NOT NULL ";
                }
                else
                {
                    sb.Append(typeStr);
                }
                sb.Append(rightPar);
                sb.Append(")");
                return sb.ToString();
            }
    

    解析表达式

    表达式树也会在这里处理,形成递归调用,当表达式是MemberExpression时,为了区分是左边的属性名还是右边的属性值,加了isRight进行区分

    当是MethodCallExpression时,如果是左边,则需要进行解析(这里没有实现),右边只需要执行方法结果即可

    /// <summary>
            /// 解析表达式
            /// </summary>
            /// <param name="exp"></param>
            /// <param name="isRight"></param>
            /// <returns></returns>
            public string RouteExpressionHandler(Expression exp, bool isRight = false)
            {
                if (exp is BinaryExpression)
                {
                    BinaryExpression be = (BinaryExpression)exp;
                    //重新拆分树,形成递归
                    return BinaryExpressionHandler(be.Left, be.Right, be.NodeType);
                }
                else if (exp is MemberExpression)
                {
                    MemberExpression mExp = (MemberExpression)exp;
                    if (isRight)//按表达式右边值
                    {
                        var obj = Expression.Lambda(mExp).Compile().DynamicInvoke();
                        if (obj is Enum)
                        {
                            obj = (int)obj;
                        }
                        return obj + "";
                    }
                    return mExp.Member.Name;//按左边的名称
                }
                else if (exp is NewArrayExpression)
                {
                    #region 数组
                    NewArrayExpression naExp = (NewArrayExpression)exp;
                    StringBuilder sb = new StringBuilder();
                    foreach (Expression expression in naExp.Expressions)
                    {
                        sb.AppendFormat(",{0}", RouteExpressionHandler(expression));
                    }
                    return sb.Length == 0 ? "" : sb.Remove(0, 1).ToString();
                    #endregion
                }
                else if (exp is MethodCallExpression)
                {
                    if (isRight)
                    {
                        return Expression.Lambda(exp).Compile().DynamicInvoke() + "";
                    }
                    //在这里解析方法
                    throw new Exception("暂不支持");
                }
                else if (exp is ConstantExpression)
                {
                    #region 常量
                    ConstantExpression cExp = (ConstantExpression)exp;
                    if (cExp.Value == null)
                        return "null";
                    else
                    {
                        return cExp.Value.ToString();
                    }
                    #endregion
                }
                else if (exp is UnaryExpression)
                {
                    UnaryExpression ue = ((UnaryExpression)exp);
                    return RouteExpressionHandler(ue.Operand, isRight);
                }
                return null;
            }
    

    转换运算符

    public string ExpressionTypeCast(ExpressionType expType)
            {
                switch (expType)
                {
                    case ExpressionType.And:
                        return "&";
                    case ExpressionType.AndAlso:
                        return " AND ";
                    case ExpressionType.Equal:
                        return "=";
                    case ExpressionType.GreaterThan:
                        return ">";
                    case ExpressionType.GreaterThanOrEqual:
                        return ">=";
                    case ExpressionType.LessThan:
                        return "<";
                    case ExpressionType.LessThanOrEqual:
                        return "<=";
                    case ExpressionType.NotEqual:
                        return "<>";
                    case ExpressionType.Or:
                        return "|";
                    case ExpressionType.OrElse:
                        return " OR ";
                    case ExpressionType.Add:
                    case ExpressionType.AddChecked:
                        return "+";
                    case ExpressionType.Subtract:
                    case ExpressionType.SubtractChecked:
                        return "-";
                    case ExpressionType.Divide:
                        return "/";
                    case ExpressionType.Multiply:
                    case ExpressionType.MultiplyChecked:
                        return "*";
                    default:
                        throw new InvalidCastException("不支持的运算符");
                }
            }
    

    获取解析值

    internal string FormatExpression(Expression<Func<T, bool>> expression)
            {
                string condition;
                var visitor = new ExpressionVisitor();
                if (expression == null)
                    return "";
                condition = visitor.RouteExpressionHandler(expression.Body);
                return condition;
            }
    

    拼接完整的SQL

    public string GetQuery()
            {
                string where = Condition;
                where = string.IsNullOrEmpty(where) ? " 1=1 " : where;
                #region group判断
                if (groupFields.Count > 0)
                {
                    where += " group by ";
                    foreach (var item in groupFields)
                    {
                        where += item + ",";
                    }
                    where = where.Substring(0, where.Length - 1);
                }
                #endregion
                string tableName = typeof(T).Name;
                string fileds = string.Join(",", queryFields);
                var part = string.Format("select {0} from {1}  where {2}", fileds, tableName, where);
                return part;
            }
    

    运行输出

    var query = new LambdaQuery<Product>();
                query.Select(b => new { b.BarCode, b.ProductName, total = b.BarCode.COUNT() });
                query.GroupBy(b => new { b.BarCode, b.ProductName });
                query.Where(b => b.ProductName == "ddd");
                query.Where(b => b.Number == 10);
                query.Where(b => b.Number == new aa().bb);//测试获取对象参数
                query.OrderBy(b => b.BarCode.COUNT(), true);
    
                Console.Write(query.GetQuery());
    

      

    这样,一般查询就能用lambda来表示了,但是一些SQL函数,是没法表示的,和之前说的一样,可以用扩展方法解决

    上面上解析方法调用表达式里,解析即可,解析方法比较复杂,就不在这里写了

    else if (exp is MethodCallExpression)
                {
                    if (isRight)
                    {
                        return Expression.Lambda(exp).Compile().DynamicInvoke() + "";
                    }
                    //在这里解析方法
                    throw new Exception("暂不支持");
                }
    

    测试例子下载 http://files.cnblogs.com/files/hubro/LambdaQueryTest2.rar

  • 相关阅读:
    移动开发 Native APP、Hybrid APP和Web APP介绍
    urllib与urllib2的学习总结(python2.7.X)
    fiddler及postman讲解
    接口测试基础
    UiAutomator2.0 和1.x 的区别
    adb shell am instrument 命令详解
    GT问题记录
    HDU 2492 Ping pong (树状数组)
    CF 567C Geometric Progression
    CF 545E Paths and Trees
  • 原文地址:https://www.cnblogs.com/hubro/p/4381337.html
Copyright © 2011-2022 走看看