本文介绍如何解析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/ ...
随机推荐
-
重温WCF之流与文件传输(七)
WCF开启流模式,主要是设置一个叫TransferMode的属性,所以,你看看哪些Binding的派生类有这个属性就可以了. TransferMode其实是一个举枚,看看它的几个有效值: Buffer ...
-
jstl格式化数字
jstl中的<fmt:formatNumber>标签 设置显示时间戳<% request.setAttribute("currentTimeStamp" ...
-
immutability-javascript
https://www.sitepoint.com/immutability-javascript/
-
Go 语言开发的基于 Linux 虚拟服务器的负载平衡平台 Seesaw
负载均衡系统 Seesaw Seesaw是由我们网络可靠性工程师用 Go 语言开发的基于 Linux 虚拟服务器的负载平衡平台,就像所有好的项目一样,这个项目也是为了解决实际问题而产生的. Seesa ...
-
MYSQL基础笔记(一)
关系型数据库概念: 1.什么是关系型数据库? 关系型数据库:是一种建立在关系模型(数学模型)上的数据库 关系模型:一种所谓建立在关系上的模型. 关系模型包含三个方面: 1.数据结构:数据存储的问题,二 ...
-
VS2010中fatal error LNK1123错误的解决方案
问题描述: 在VS2010项目编译时会出现如下错误:LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏 解决方案: 查找是否有两个cvtres.exe ...
-
mysql__存储过程
1.存储过程相当于我们学的各种高级语言的函数,既然是函数就可能有参数,先介绍参数类型: 存储过程主要包含三种参数类型,注意我说的不是数据类型(INT.VARCHAR) 第一种:IN输入参数:表示这种参 ...
-
Linux下关闭Tomcat残留线程
ps -ef | grep tomcat kill -9 {pid}
-
DotNet进阶系列
一. 回顾历史 回顾个人发展历程,自2012年初次接触开发至今(2018年)已经有六个年头,这期间陆陆续续学习并掌握了不少技术,C#语言.ORM框架.多线程技术.设计模式.前端技术.MVC.MVVM框 ...
-
CentOS7安装GitLab服务
安装GitLab服务 1.安装必要依赖 yum install -y curl policycoreutils openssh-server openssh-clients postfix 2.下载安 ...