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
ORM开发之解析lambda实现group查询(附测试例子)的更多相关文章
- ORM开发之解析lambda实现完整查询(附测试例子)
上次讲解了怎么解析匿名对象(ORM开发之解析lambda实现group查询),这次来实现解析二元运算,完成基本条件语法 先看一个表达式 query.Where(b => b.Number == ...
- 完爆Facebook/GraphQL,APIJSON全方位对比解析(三)-表关联查询
相关阅读: 完爆Facebook/GraphQL,APIJSON全方位对比解析(一)-基础功能 完爆Facebook/GraphQL,APIJSON全方位对比解析(二)-权限控制 自APIJSON发布 ...
- c++::Mysql::ORM 开发环境搭建
官网地址:https://www.codesynthesis.com/products/odb/ 环境搭建:ubuntu16.04-64 1.安装mysqlClient sudo apt-get in ...
- visio二次开发——图纸解析之线段
多写博客,其实还是蛮好的习惯的,当初大学的时候导师就叫我写,但是就是懒,大学的时候,谁不是魔兽或者LOL呢,是吧,哈哈哈. 好了,接着上一篇visio二次开发——图纸解析,我继续写. 摘要: (转发请 ...
- iOS开发 XML解析和下拉刷新,上拉加载更多
iOS开发 XML解析和下拉刷新,上拉加载更多 1.XML格式 <?xml version="1.0" encoding="utf-8" ?> 表示 ...
- java微信开发API解析(二)-获取消息和回复消息
java微信开发API解析(二)-获取消息和回复消息 说明 * 本演示样例依据微信开发文档:http://mp.weixin.qq.com/wiki/home/index.html最新版(4/3/20 ...
- Solr --- Group查询与Facet区别
简介 facet的查询结果主要是分组信息:有什么分组,每个分组包括多少记录:但是分组中有哪些数据是不可知道的,只有进一步搜索. group则类似于关系数据库的group by,可以用于一个或者几个字段 ...
- Spring注解开发-全面解析常用注解使用方法之生命周期
本文github位置:https://github.com/WillVi/Spring-Annotation/ 往期文章:Spring注解开发-全面解析常用注解使用方法之组件注册 bean生命周期 ...
- C#/ASP.NET MVC微信公众号接口开发之从零开发(四) 微信自定义菜单(附源码)
C#/ASP.NET MVC微信接口开发文章目录: 1.C#/ASP.NET MVC微信公众号接口开发之从零开发(一) 接入微信公众平台 2.C#/ASP.NET MVC微信公众号接口开发之从零开发( ...
随机推荐
- 用Node.js发送邮件
本文讲的是用Node.js通过一个开启smtp的已有的邮箱账号发送邮件,而不是如何创建一个邮件服务器 开启smtp服务 首先要去要使用的邮箱中设置开启smtp,才能正常发送邮件 这边以163邮箱为例 ...
- Android中获取选择图片与获取拍照返回结果差异
导语: 如今的安卓应用在选择图片的处理上大多合并使用拍照和从相册中选择这两种方式 今天在写一个这样的功能时遇到一个尴尬的问题,同样是拍照获取图片功能,在不同手机上运行的效果不一样,下面是在某型手机上测 ...
- 【hihoCoder】1148:2月29日
问题:http://hihocoder.com/problemset/problem/1148 给定两个日期,计算这两个日期之间有多少个2月29日(包括起始日期). 思路: 1. 将问题转换成求两个日 ...
- Unity自动寻路Navmesh之入门
实例 我们要实现一个功能:点击场景中的一个位置,角色可以自动寻路过去.角色会绕过各种复杂的障碍,找到一条理论上”最短路径“. 步骤 1.创建地形 2.添加角色 3.创建多个障碍物,尽量摆的复杂一点,来 ...
- 网站中使用中文个性字库字体--@font-face解决方案探索 l(转)
最近的项目有用到特别中文字体,最终效果如下图: 红线标记处均为字体,可选中,交互起来,比图片方便太多了. 解决思路就是将体积巨大的中文字库,取子集,只包涵要使用的那部分文字,因此体积就很小了(包含10 ...
- c/c++头文件_string
string, cstring, string.h 一.string头文件 主要包含一些字符串转换的函数 // sto* NARROW CONVERSIONS// sto* WIDE CONVERSI ...
- WebView解析
WebView解析 WebView是一个基于Webkit的,相当于内置浏览器的强大功能的组件,WebView的使用这么分四步说明:添加组件,加载资源,属性设置,辅助功能. 一.WebView的添加 ...
- IOS第三天-新浪微博 - 版本新特性,OAuth授权认证
*********版本新特性 #import "HWNewfeatureViewController.h" #import "HWTabBarViewController ...
- 事务使用中如何避免误用分布式事务(System.Transactions.TransactionScope)
1:本地事务DbTransaction和分布式事务TransactionScope的区别: 1.1:System.Data.Common.DbTransaction: 本地事务:这个没什么好说了,就是 ...
- 优秀网站看前端 —— 小米Note介绍页面
刚开始经营博客的时候,我写过不少“扒皮”系列的文章,主要介绍一些知名站点上有趣的交互效果,然后试着实现它们.后来开始把注意力挪到一些新颖的前端技术上,“扒皮”系列便因此封笔多时.今天打算重开“扒皮”的 ...