目的:以编程方式实现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

ORM开发之解析lambda实现group查询(附测试例子)的更多相关文章

  1. ORM开发之解析lambda实现完整查询(附测试例子)

    上次讲解了怎么解析匿名对象(ORM开发之解析lambda实现group查询),这次来实现解析二元运算,完成基本条件语法 先看一个表达式 query.Where(b => b.Number == ...

  2. 完爆Facebook/GraphQL,APIJSON全方位对比解析(三)-表关联查询

    相关阅读: 完爆Facebook/GraphQL,APIJSON全方位对比解析(一)-基础功能 完爆Facebook/GraphQL,APIJSON全方位对比解析(二)-权限控制 自APIJSON发布 ...

  3. c++::Mysql::ORM 开发环境搭建

    官网地址:https://www.codesynthesis.com/products/odb/ 环境搭建:ubuntu16.04-64 1.安装mysqlClient sudo apt-get in ...

  4. visio二次开发——图纸解析之线段

    多写博客,其实还是蛮好的习惯的,当初大学的时候导师就叫我写,但是就是懒,大学的时候,谁不是魔兽或者LOL呢,是吧,哈哈哈. 好了,接着上一篇visio二次开发——图纸解析,我继续写. 摘要: (转发请 ...

  5. iOS开发 XML解析和下拉刷新,上拉加载更多

    iOS开发 XML解析和下拉刷新,上拉加载更多 1.XML格式 <?xml version="1.0" encoding="utf-8" ?> 表示 ...

  6. java微信开发API解析(二)-获取消息和回复消息

    java微信开发API解析(二)-获取消息和回复消息 说明 * 本演示样例依据微信开发文档:http://mp.weixin.qq.com/wiki/home/index.html最新版(4/3/20 ...

  7. Solr --- Group查询与Facet区别

    简介 facet的查询结果主要是分组信息:有什么分组,每个分组包括多少记录:但是分组中有哪些数据是不可知道的,只有进一步搜索. group则类似于关系数据库的group by,可以用于一个或者几个字段 ...

  8. Spring注解开发-全面解析常用注解使用方法之生命周期

    本文github位置:https://github.com/WillVi/Spring-Annotation/ 往期文章:Spring注解开发-全面解析常用注解使用方法之组件注册 bean生命周期 ​ ...

  9. C#/ASP.NET MVC微信公众号接口开发之从零开发(四) 微信自定义菜单(附源码)

    C#/ASP.NET MVC微信接口开发文章目录: 1.C#/ASP.NET MVC微信公众号接口开发之从零开发(一) 接入微信公众平台 2.C#/ASP.NET MVC微信公众号接口开发之从零开发( ...

随机推荐

  1. dubbo 常见错误

    1. Caused by: java.lang.reflect.MalformedParameterizedTypeException 或 Caused by: java.lang.NoSuchMet ...

  2. common.js js中常用方法

    //创建CSS样式段 //classid: CSS样式段ID//font: 字体//size: 字体大小//color: 字体颜色//style: 字体风格function FCMakeCSSClas ...

  3. 【转载】用Ionic开发hybrid APP

    使用phonegap开发APP的优劣在此不必细说,快速,简单,跨平台,以及随着iOS,Android本身对webview优化所带来的不错的性能,便是其独有的优势.而且私以为在目前激烈而又变化快速的移动 ...

  4. Spark 应用程序调优

    对于很多刚接触Spark的人来说,可能主要关心数据处理的逻辑,而对于如何高效运行Spark应用程序了解较少.由于Spark是一种分布式内存计算框架,其性能往往受限于CPU.内存.网络等多方面的因素,对 ...

  5. bzoj3380+3381+3382+3383 Usaco2004 Open

    四道比较水的题 T1:SPFA+状压 #include<stdio.h> #include<string.h> #include<algorithm> #inclu ...

  6. java中类的加载情况

    当一个类存在继承且与其他类有关联情况时,类中各模块加载顺序如下: 1.首先找到public类,判断该类是否继承其他类,如果没有继承其他类(Object类除外),则加载该类:否则转去加载该类的超类,超类 ...

  7. TLogger一个D7可用的轻量级日志

    今天调程序,要用到日志.XE7有Qlog,D7用什么 从网上找到了Logger,下载的原文是不支持D7的,不过也只是很少的地方不同,自己修改了下就可以用了 感谢原作者和红鱼的分享 unit Logge ...

  8. iOS开发系列--C语言之构造类型

    概述 在第一节中我们就提到C语言的构造类型,分为:数组.结构体.枚举.共用体,当然前面数组的内容已经说了很多了,这一节将会重点说一下其他三种类型. 结构体 枚举 共用体 结构体 数组中存储的是一系列相 ...

  9. Windows Azure Storage (6) Windows Azure Storage之Table

    <Windows Azure Platform 系列文章目录> 最近想了想,还是有必要把Windows Azure Table Storage 给说清楚. 1.概念 Windows Azu ...

  10. 谁占了我的端口 for Windows

    这篇文章发布于我的 github 博客:原文 今天在本地调试 Blog 的时候意外的出现了一些错误:127.0.0.1 4000 端口已经被其他的进程占用了.如何找到占用端口的进程呢? Configu ...