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

    目的:以编程方式实现group查询,在开发ORM时,需要达到这样的效果

    先看一个简单的group语句

    select BarCode,ProductName,COUNT(BarCode) as total from ProductData  group by BarCode,ProductName
    order by COUNT(BarCode) desc

      结果

    BarCode                        ProductName                    total
    ------------------------------ ------------------------------ -----------
    1212122                        product2                       4
    21312313                       product3                       2
    

      group语法分解为

    • 查询哪些字段 BarCode,ProductName,COUNT(BarCode) as total 
    • 按哪些字段进行分组 group by BarCode,ProductName
    • 按什么排序  order by COUNT(BarCode) desc

    linq to sql 表示为

    from p in  ProductData
    group p.BarCode by p.ProductName into g
    select  new 
    {
    g.BarCode,
    g.ProductName,
    total=g.Count()
    }

    linq to sql很容易表达,用lambda该如何表达呢 

    跟普通SQL查询不同,查询字段和排序可用聚合函数count,sum,抛开这,用lambda,同样的查询可表示为

    这里用匿名对象来作选择器

    设定 query=new LambdaQuery<Product>() 以下方法可能不实际存在,只作演示

    query.Select(b=>new{b.BarCode,b.ProductName})
    
    .GroupBy(b=>new{b.BarCode,b.ProductName})
    
    .OrderBy(b=>b.BarCode,true);

    query.Select(b=>new{b.BarCode,b.ProductName}) 能表示 select BarCode,ProductName 

    但匿名对象可没Count(b.ProductName)这样的语法,所以没法生成select count(BarCode)这样的语法

    没有直接的方法,但是有间接的方法,扩展方法 扩展方法真是个好东西,解决了很多问题
    定义一个扩展方法,名称定义为大写,为避免冲突
    public static int COUNT(this object origin)
            {
                return 0;
            }
    

    所有object对象将会有COUNT()方法

    将上面语法进行改进为

    query.Select(b=>new{b.BarCode,b.ProductName,total=b.BarCode.COUNT()})
    

      以这样形式进行表示,这样在语法上是编译通过的,并且lambda支持这样的解析

    完整表示改为

    query.Select(b=>new{b.BarCode,b.ProductName,total=b.BarCode.COUNT()})
    
    .GroupBy(b=>new{b.BarCode,b.ProductName})
    
    .OrderBy(b=>b.BarCode.COUNT(),true);
    

      这样,完整的group表示语法就完成了,致少在逻辑上,是能实现SQL的group语法了,剩下就需要进行解析了

    定义参数

    public List<string> queryFields = new List<string>();
            public List<string> queryOrderBy = new List<string>();
            public List<string> groupFields = new List<string>();
    

      

    //此方法解析方法调用表达式的属性名和方法名
    string GetPropertyMethod(Expression item,out string methodName)
            { //转换为方法表达式
                var method = item as MethodCallExpression;
                MemberExpression memberExpression;            //获取访问属性表达式
                if (method.Arguments[0] is UnaryExpression)
                {
                    memberExpression = (method.Arguments[0] as UnaryExpression).Operand as MemberExpression;
                }
                else
                {
                    memberExpression = method.Arguments[0] as MemberExpression;
                }
                methodName = method.Method.Name;//调用的方法名
                return memberExpression.Member.Name;//返回访问的属性名
            }

    解析Select

    public LambdaQuery<T> Select<TResult>(Expression<Func<T, TResult>> resultSelector)
            {
                string queryFullName = "";
                var newExpression = resultSelector.Body as NewExpression;//转换为匿名对象表达式
                int i = 0;
                foreach (var item in newExpression.Arguments)//遍历所有参数
                {
                    var memberName = newExpression.Members[i].Name;//获取构造的属性名
                    if (item is MethodCallExpression)//如果是方法
                    {
                        string methodName;
                        string propertyName = GetPropertyMethod(item, out methodName);//获取方法名和属性名
                        queryFullName = string.Format("{0}({1}) as {2}", methodName, propertyName, memberName);
                    }
                    else//直接属性
                    {
                        var memberExpression = item as MemberExpression;//转换为属性访问表达式
                        queryFullName = memberExpression.Member.Name;//返回属性名
                    }
                    queryFields.Add(queryFullName);
                    i += 1;
                }
                
                return this;
            }
    

      

     解析OrderBy,过程和上面差不多

    public LambdaQuery<T> OrderBy<TKey>(Expression<Func<T, TKey>> expression, bool desc = true)
            {
                string orderBy="";
                string name;
                if (expression.Body is MethodCallExpression)//如果是方法
                {
                    string methodName;
                    string propertyName = GetPropertyMethod(expression.Body, out methodName);
                    name = string.Format("{1}({0})", propertyName, methodName);
                    orderBy = string.Format(" {0} {1}", name, desc ? "desc" : "asc");
                }
                else
                {
                    MemberExpression mExp = (MemberExpression)expression.Body;
                    if (!string.IsNullOrEmpty(orderBy))
                    {
                        orderBy += ",";
                    }
                    name = mExp.Member.Name;
                    orderBy = string.Format(" {0} {1}", name, desc ? "desc" : "asc");
                }
                queryOrderBy.Add(orderBy);
                return this;
            }
    

      解析GroupBy

    public LambdaQuery<T> GroupBy<TResult>(Expression<Func<T, TResult>> resultSelector)
            {
                foreach (var item in (resultSelector.Body as NewExpression).Arguments)
                {
                    var memberExpression = item as MemberExpression;//转换为属性访问表达式
                    groupFields.Add(memberExpression.Member.Name);
                }
                return this;
            }
    

      输出

    string fileds=string.Join(",",query.queryFields);
                string groupFields = string.Join(",", query.groupFields);
                string queryOrderBy = string.Join(",", query.queryOrderBy);
                Console.Write(string.Format("select {0} from Product group by {1} order by {2}", fileds, groupFields, queryOrderBy));
    

    结果截图

    上面只实现了匿名对象简单的解析,ORM查询复杂的的是二元运算解析,如:

    query.Where(b=>b.Id>10&&b.Name="hubro");

    这样就需要解析表达式树了,情况比较复杂,回头整理一下

    实现表达式树解析后就能实现having语法了,linq实现的group用lambda也能完整实现了

    此示例只是实现lambda到SQL语句之间的转换,实际应用需要考虑参数化,结果集映射,路还很长,有兴趣的欢迎关注CRL框架

    TO:管理员 现在达到放在首页的要求了吧???

    例子下载地址:http://files.cnblogs.com/files/hubro/LambdaQueryTest.rar

  • 相关阅读:
    Spring经典视频教程大集合
    使用jsonlib进行Java和JSON之间的转换
    c:import Unable to get RequestDispatcher for Context
    打开IE都会弹出欢迎界面“欢迎使用Internet Explorer 8”
    Struts2 标签 用法示例 (
    as3相关的frameworks
    as相关的框架引擎应用集合
    init
    XNA框架基础——疑难解答
    XNA框架基础——XNA的注意事项
  • 原文地址:https://www.cnblogs.com/hubro/p/4371588.html
Copyright © 2011-2022 走看看