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

  • 相关阅读:
    高精度计算
    高精度除以低精度
    P1258 小车问题
    POJ 2352 stars (树状数组入门经典!!!)
    HDU 3635 Dragon Balls(超级经典的带权并查集!!!新手入门)
    HDU 3938 Portal (离线并查集,此题思路很强!!!,得到所谓的距离很巧妙)
    POJ 1703 Find them, Catch them(确定元素归属集合的并查集)
    HDU Virtual Friends(超级经典的带权并查集)
    HDU 3047 Zjnu Stadium(带权并查集,难想到)
    HDU 3038 How Many Answers Are Wrong(带权并查集,真的很难想到是个并查集!!!)
  • 原文地址:https://www.cnblogs.com/hubro/p/4381337.html
Copyright © 2011-2022 走看看