用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/ ...
随机推荐
- Automotive Security的一些资料和心得(5):Privacy
1. Introduction 1.1 "Customers own their data and we can be no more than the trsted stewards of ...
- Highcharts资料
对应的API: http://api.hcharts.cn/#chart.events 对应的中文网实例:http://www.hcharts.cn/demo/highcharts/dynamic ...
- Linux fdisk 命令
Linux fdisk 命令 fdisk fdisk功能说明:磁盘分区.语 法:fdisk [-b <分区大小>][-uv][外围设备代号] ...
- [Jquery] Jquery获取浏览器宽高的代码
<script type="text/javascript"> $(document).ready(function() { alert($(window).heigh ...
- HDU 2045 不容易系列之(3)—— LELE的RPG难题(递推)
点我看题目 题意 : 中文题不解释. 思路 :先算了第3个第4个,算的时候发现只要在已经枚举出来的前边的状态中往后添加字母就行了,如果两个的都已经表示出来了,那第三个就可以在每个第二个后边加一个,在 ...
- HDU4519
一种比较挫的写法 /* 模拟 */ #include<stdio.h> #include<string.h> #include<stdlib.h> #include ...
- 服务器部署_centos 安装jdk手记
1. 下载jdk略. 2. 将jdk相关文件目录放到指定目录 (1) 创建jdk目录 /usr/java/jdk7 mkdir -p /usr/java/jdk7 (2) 解压缩jdk压缩包,并移动至 ...
- MongoDB实战指南(五):MongoDB中的聚集分析
聚集操作是对数据进行分析的有效手段.MongoDB主要提供了三种对数据进行分析计算的方式:管道模式聚集分析,MapReduce聚集分析,简单函数和命令的聚集分析. 1. 管道模式进行聚集 这里所说的管 ...
- 李洪强漫谈iOS开发[C语言-018]-scanf函数
- easyui源码翻译1.32--PropertyGrid(属性表格)
前言 继承自$.fn.datagrid.defaults.使用$.fn.propertygrid.defaults重写默认值对象.下载该插件翻译源码 属性表格提供The propertygrid pr ...