用lambda构建ORM查询语句
本文介绍如何解析lambda表达式来获取一个满足条件的查询语句。
先看个截图
通过设置实体对象Article_Content的查询表达式,就可以获取对应的参数化SQL语句,使用起来很方便,减少了代码的书写,同时提高了安全性。
本文需要了解的基础知识有:
- lambda表达式
- Expression表达式树
- 扩展方法
首先,我们应该有一个普通的实体对象和它的基类
- //基类
- class baseEntity
- {
- internal Expression whereFunc;
- }
- //实体对象
- class Article_Content : baseEntity
- {
- public int? Article_Id { get; set; }
- public string Article_Title { get; set; }
- public string Article_SourceUrl { get; set; }
- }
- /// <summary>
- /// 设置匹配表达式
- /// </summary>
- public static void SetWhereFunc<T>(this T entity, Expression<Func<T, bool>> func) where T : baseEntity
- {
- entity.whereFunc = func;
- }
- 好了。这个时候我们可以写出类似下面的代码了:
- Article_Content art = new Article_Content();
- art.SetWhereFunc(ar=>ar.Aritlce_Id == 4 && ar.Article_Title == "sss");
- public static bool In<T>(this T obj, T[] array)
- {
- return true;
- }
- public static bool Like(this string str, string likeStr)
- {
- return true;
- }
这个时候很现在,我们的SetWhereFunc可以写出如下的代码了:
- art.SetWhereFunc(ar=>ar.Aritlce_Id.In(new int?[]{4,6}) && ar.Article_Title.Like("%sss"));
- 到目前为止,前台编写方式已经解决了。
- 剩下的就是如何来分析我们设置的这个lambda表达式了。
- 当然分析lambda表达式的时候,我们还需要考虑生成的SQL语句的参数化。这个时候还需要另一个数据操作对象:
- public abstract class DbOperate
- {
- /// <summary>
- /// 获取此数据类型的参数形式表现
- /// </summary>
- /// <param name="fieldsName"></param>
- /// <returns></returns>
- public abstract string GetParamFlag(string fieldsName);
- //其他操作方法.....
- }
- internal static string Where<T>(this T entity, Expression func, DbOperate dbop, ref ArrayList alParamNames, ref ArrayList alParamValues) where T : baseEntity
- {
- return ExpressionRouter(func, dbop, ref alParamNames, ref alParamValues);
- }
- lambda表达式也是表达式的一种。那么我们可以通过分析表达式的类型计算对应的产生式。
- 现在主要遇到的表达式有以下几种:
- BinaryExpression
- LambdaExpression
- MethodCallExpression
- MemberExpression
- ConstantExpression
- NewArrayExpression
- UnaryExpression
根据不同的类型,可以进行不同操作,为了简单起见,我们这里演示的是直接拼接字符串的方式,各位可以自己尝试使用参数的方式,函数原型在上面了。
- static string BinarExpressionProvider(Expression left, Expression right, ExpressionType type)
- {
- string sb = "(";
- //先处理左边
- sb += ExpressionRouter(left);
- sb += ExpressionTypeCast(type);
- //再处理右边
- string tmpStr = ExpressionRouter(right);
- if (tmpStr == "null")
- {
- if (sb.EndsWith(" ="))
- sb = sb.Substring(0, sb.Length - 2) + " is null";
- else if (sb.EndsWith("<>"))
- sb = sb.Substring(0, sb.Length - 2) + " is not null";
- }
- else
- sb += tmpStr;
- return sb += ")";
- }
- //表达式路由计算
- static string ExpressionRouter(Expression exp)
- {
- string sb = string.Empty;
- if (exp is BinaryExpression)
- {
- BinaryExpression be = ((BinaryExpression)exp);
- return BinarExpressionProvider(be.Left, be.Right, be.NodeType);
- }
- else if (exp is MemberExpression)
- {
- MemberExpression me = ((MemberExpression)exp);
- return me.Member.Name;
- }
- else if (exp is NewArrayExpression)
- {
- NewArrayExpression ae = ((NewArrayExpression)exp);
- StringBuilder tmpstr = new StringBuilder();
- foreach (Expression ex in ae.Expressions)
- {
- tmpstr.Append(ExpressionRouter(ex));
- tmpstr.Append(",");
- }
- return tmpstr.ToString(0, tmpstr.Length - 1);
- }
- else if (exp is MethodCallExpression)
- {
- MethodCallExpression mce = (MethodCallExpression)exp;
- if (mce.Method.Name == "Like")
- return string.Format("({0} like {1})", ExpressionRouter(mce.Arguments[0]), ExpressionRouter(mce.Arguments[1]));
- else if (mce.Method.Name == "NotLike")
- return string.Format("({0} Not like {1})", ExpressionRouter(mce.Arguments[0]), ExpressionRouter(mce.Arguments[1]));
- else if (mce.Method.Name == "In")
- return string.Format("{0} In ({1})", ExpressionRouter(mce.Arguments[0]), ExpressionRouter(mce.Arguments[1]));
- else if (mce.Method.Name == "NotIn")
- return string.Format("{0} Not In ({1})", ExpressionRouter(mce.Arguments[0]), ExpressionRouter(mce.Arguments[1]));
- }
- else if (exp is ConstantExpression)
- {
- ConstantExpression ce = ((ConstantExpression)exp);
- if (ce.Value == null)
- return "null";
- else if (ce.Value is ValueType)
- return ce.Value.ToString();
- else if (ce.Value is string || ce.Value is DateTime || ce.Value is char)
- return string.Format("'{0}'", ce.Value.ToString());
- }
- else if (exp is UnaryExpression)
- {
- UnaryExpression ue = ((UnaryExpression)exp);
- return ExpressionRouter(ue.Operand);
- }
- return null;
- }
- static string ExpressionTypeCast(ExpressionType type)
- {
- switch (type)
- {
- case ExpressionType.And:
- 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:
- 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:
- return null;
- }
- }
下面是文章一开始的那个lambda表达式分析出来的对应的where语句
对应的参数和参数值顺序是一一对应的。
我这里的对Expression表达式进行了计算,所以最后一个参数对应的
- string.Concat(GetStr(7), "sdfsdf".Length, "sssss" + GetStr(6)).ToUpper()
这个表达式已经被计算完成得到"GOOD76SSSSSGOOD6",GetStr(int)函数见第一张截图。
这里主要体会的是用Expression Tree的一个实际用法。实际跑起来体会下就能明白。要说的话实在内容太多。而前面的都介绍都是概念性的.
代码下载地址:http://download.csdn.net/detail/ysq5202121/4263117
用lambda构建ORM查询语句的更多相关文章
- hisql ORM 查询语句使用教程
HiSql 提供一个可以适合多种数据库的中间查询语法,不需要关注各个数据库的语法特性,通过HiSql写语句可以在常用的不同类型数据库中执行,且语法与Sql语境类似一看就懂一学就会 hisql.net ...
- SpringBoot使用注解的方式构建Elasticsearch查询语句,实现多条件的复杂查询
背景&痛点 通过ES进行查询,如果需要新增查询条件,则每次都需要进行硬编码,然后实现对应的查询功能.这样不仅开发工作量大,而且如果有多个不同的索引对象需要进行同样的查询,则需要开发多次,代码复 ...
- ORM查询条件
模板: from django.db import models class Article(models.Model): title = models.CharField(max_length=20 ...
- Django(17)orm查询操作
前言 查找是数据库操作中一个非常重要的技术.查询一般就是使用filter.exclude以及get三个方法来实现.我们可以在调用这些方法的时候传递不同的参数来实现查询需求.在ORM层面,这些查询条件都 ...
- ORM开发之解析lambda实现group查询(附测试例子)
目的:以编程方式实现group查询,在开发ORM时,需要达到这样的效果 先看一个简单的group语句 select BarCode,ProductName,COUNT(BarCode) as tota ...
- ORM开发之解析lambda实现完整查询(附测试例子)
上次讲解了怎么解析匿名对象(ORM开发之解析lambda实现group查询),这次来实现解析二元运算,完成基本条件语法 先看一个表达式 query.Where(b => b.Number == ...
- 浅谈sql 、linq、lambda 查询语句的区别
浅谈sql .linq.lambda 查询语句的区别 LINQ的书写格式如下: from 临时变量 in 集合对象或数据库对象 where 条件表达式 [order by条件] select 临时变量 ...
- 第二十篇ORM查询与SQL语句
ORM查询与SQL语句 多表操作 创建模型 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄. 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息.作者详情 ...
- Lambda表达式转SQL语句类库
/* 作者:道法自然 * 个人邮件:myyangbin@sina.cn * 2014-10-1 */ Lambda表达式转SQL语句类库源码下载:http://download.csdn.net/ ...
随机推荐
- python 读写文本文件
本人最近新学python ,用到文本文件的读取,经过一番研究,从网上查找资料,经过测试,总结了一下读取文本文件的方法. 1.在读取文本文件的时无非有两种方法: a.f=open('filename', ...
- linux删除某类型文件的命令
使用linux命令行,删除某目录下某类型的文件,如:删除.rar结尾的所有文件. 命令如下: find . -name "*.rar" -type f -print -exec r ...
- 从某一日期开始过day天的日期
一个SX问我的,我就写了写......从2010.1.1开始,给了一组测试数据3的话输出2010.1.4星期1,所以说2010.1.1是星期五,总星期就是 (day+5)%7==0?7:(day+5) ...
- 各大搜索引擎的User-Agent
baidu:Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html) Google:Moz ...
- ListView 长按拖动会变黑的解决方案
在ListView的xml文件中添加这个属性: android:cacheColorHint="#00000000"
- php smarty foreach循环注意
在template中,要注意{foreach from=$arr item=value}其中的value不需要$美元符号
- code forces Jeff and Periods
/* * c.cpp * * Created on: 2013-10-7 * Author: wangzhu */ #include<cstdio> #include<iostrea ...
- easyui源码翻译1.32--accordion(手风琴)
前言 前几天加班比较忙 未能及时更新翻译的 今天多发布几篇..下载该插件翻译源码 Accordion 分类空间允许用户使用多面板,但在同一时间只会显示一个.每个面板都内建支持展开和折叠功能.点击一个面 ...
- 各种HTTP错误消息含义
错误代码 错误消息 400 无法解析此请求. 401.1 未经授权:访问由于凭据无效被拒绝. 401.2 未经授权: 访问由于服务器配置倾向使用替代身份验证方法而被拒绝. 401.3 未经授权:访问由 ...
- 关于百度地图API的地图坐标转换问题
原文:关于百度地图API的地图坐标转换问题 我在之前的文章利用html5获取经纬度并且在百度地图中显示位置中使用了百度地图的API来显示html5获取的地理位置,在文中我说过这样的话,我说百度地图的准 ...