本文介绍如何解析lambda表达式来获取一个满足条件的查询语句。

先看个截图 

通过设置实体对象Article_Content的查询表达式,就可以获取对应的参数化SQL语句,使用起来很方便,减少了代码的书写,同时提高了安全性。

本文需要了解的基础知识有:

  1. lambda表达式
  2. Expression表达式树
  3. 扩展方法

首先,我们应该有一个普通的实体对象和它的基类

  1. //基类
  2. class baseEntity
  3. {
  4. internal Expression whereFunc;
  5. }
  1. //实体对象
  2. class Article_Content : baseEntity
  3. {
  4. public int? Article_Id { get; set; }
  5. public string Article_Title { get; set; }
  6. public string Article_SourceUrl { get; set; }
  7. }
这个时候我们需要定义一些扩展方法以便对实体的查询表达式进行保存。我们的SQL语句的需求是要参数化的。所以,在实体对象这里还不知道数据库类型,没有办法获取对应的参数化符号。
  1. /// <summary>
  2. /// 设置匹配表达式
  3. /// </summary>
  4. public static void SetWhereFunc<T>(this T entity, Expression<Func<T, bool>> func) where T : baseEntity
  5. {
  6. entity.whereFunc = func;
  7. }
  1. 好了。这个时候我们可以写出类似下面的代码了:
  1. Article_Content art = new Article_Content();
  2. art.SetWhereFunc(ar=>ar.Aritlce_Id == 4 && ar.Article_Title == "sss");
但是SQL语句中很常见的Like查询似乎还没有办法实现。
 
我们通过分析Where子句,发现where语句的做事然筛选出来的纪录要满足where子句的条件,那么where子句返回的就是一个bool,where子句其实是一个逻辑表达式。所以,就有了刚才SetWhereFunc函数里面的第二个参数中Func的返回值是bool。
 
既然where子句要求返回的是一个bool表达式同理:Like、In、Not等表达方法我们也只能让它返回的是bool值;
那么就有了下面的扩展函数:
  1. public static bool In<T>(this T obj, T[] array)
  2. {
  3. return true;
  4. }
  5. public static bool Like(this string str, string likeStr)
  6. {
  7. return true;
  8. }

这个时候很现在,我们的SetWhereFunc可以写出如下的代码了:

  1. art.SetWhereFunc(ar=>ar.Aritlce_Id.In(new int?[]{4,6}) && ar.Article_Title.Like("%sss"));
  1. 到目前为止,前台编写方式已经解决了。
  1. 剩下的就是如何来分析我们设置的这个lambda表达式了。
  1. 当然分析lambda表达式的时候,我们还需要考虑生成的SQL语句的参数化。这个时候还需要另一个数据操作对象:
  1. public abstract class DbOperate
  2. {
  3. /// <summary>
  4. /// 获取此数据类型的参数形式表现
  5. /// </summary>
  6. /// <param name="fieldsName"></param>
  7. /// <returns></returns>
  8. public abstract string GetParamFlag(string fieldsName);
  9. //其他操作方法.....
  1. }
这个对象还有其他方法,不过在这里,我们主要使用的就是这样一个参数标识,如果它在MSSQL里,它返回的是@+fieldName,Orcale则返回的是:fieldName。
在构建SQL语句的时候,我们同样也使用扩展方法来解析表达式。
  1. internal static string Where<T>(this T entity, Expression func, DbOperate dbop, ref ArrayList alParamNames, ref ArrayList alParamValues) where T : baseEntity
  2. {
  3. return ExpressionRouter(func, dbop, ref alParamNames, ref alParamValues);
  4. } 
  1. lambda表达式也是表达式的一种。那么我们可以通过分析表达式的类型计算对应的产生式。
  1. 现在主要遇到的表达式有以下几种:
  1. BinaryExpression
  2. LambdaExpression
  3. MethodCallExpression
  4. MemberExpression
  5. ConstantExpression
  6. NewArrayExpression
  7. UnaryExpression

根据不同的类型,可以进行不同操作,为了简单起见,我们这里演示的是直接拼接字符串的方式,各位可以自己尝试使用参数的方式,函数原型在上面了。

  1. static string BinarExpressionProvider(Expression left, Expression right, ExpressionType type)
  2. {
  3. string sb = "(";
  4. //先处理左边
  5. sb += ExpressionRouter(left);
  6. sb += ExpressionTypeCast(type);
  7. //再处理右边
  8. string tmpStr = ExpressionRouter(right);
  9. if (tmpStr == "null")
  10. {
  11. if (sb.EndsWith(" ="))
  12. sb = sb.Substring(0, sb.Length - 2) + " is null";
  13. else if (sb.EndsWith("<>"))
  14. sb = sb.Substring(0, sb.Length - 2) + " is not null";
  15. }
  16. else
  17. sb += tmpStr;
  18. return sb += ")";
  19. }
  20. //表达式路由计算
  21. static string ExpressionRouter(Expression exp)
  22. {
  23. string sb = string.Empty;
  24. if (exp is BinaryExpression)
  25. {
  26. BinaryExpression be = ((BinaryExpression)exp);
  27. return BinarExpressionProvider(be.Left, be.Right, be.NodeType);
  28. }
  29. else if (exp is MemberExpression)
  30. {
  31. MemberExpression me = ((MemberExpression)exp);
  32. return me.Member.Name;
  33. }
  34. else if (exp is NewArrayExpression)
  35. {
  36. NewArrayExpression ae = ((NewArrayExpression)exp);
  37. StringBuilder tmpstr = new StringBuilder();
  38. foreach (Expression ex in ae.Expressions)
  39. {
  40. tmpstr.Append(ExpressionRouter(ex));
  41. tmpstr.Append(",");
  42. }
  43. return tmpstr.ToString(0, tmpstr.Length - 1);
  44. }
  45. else if (exp is MethodCallExpression)
  46. {
  47. MethodCallExpression mce = (MethodCallExpression)exp;
  48. if (mce.Method.Name == "Like")
  49. return string.Format("({0} like {1})", ExpressionRouter(mce.Arguments[0]), ExpressionRouter(mce.Arguments[1]));
  50. else if (mce.Method.Name == "NotLike")
  51. return string.Format("({0} Not like {1})", ExpressionRouter(mce.Arguments[0]), ExpressionRouter(mce.Arguments[1]));
  52. else if (mce.Method.Name == "In")
  53. return string.Format("{0} In ({1})", ExpressionRouter(mce.Arguments[0]), ExpressionRouter(mce.Arguments[1]));
  54. else if (mce.Method.Name == "NotIn")
  55. return string.Format("{0} Not In ({1})", ExpressionRouter(mce.Arguments[0]), ExpressionRouter(mce.Arguments[1]));
  56. }
  57. else if (exp is ConstantExpression)
  58. {
  59. ConstantExpression ce = ((ConstantExpression)exp);
  60. if (ce.Value == null)
  61. return "null";
  62. else if (ce.Value is ValueType)
  63. return ce.Value.ToString();
  64. else if (ce.Value is string || ce.Value is DateTime || ce.Value is char)
  65. return string.Format("'{0}'", ce.Value.ToString());
  66. }
  67. else if (exp is UnaryExpression)
  68. {
  69. UnaryExpression ue = ((UnaryExpression)exp);
  70. return ExpressionRouter(ue.Operand);
  71. }
  72. return null;
  73. }
  74. static string ExpressionTypeCast(ExpressionType type)
  75. {
  76. switch (type)
  77. {
  78. case ExpressionType.And:
  79. case ExpressionType.AndAlso:
  80. return " AND ";
  81. case ExpressionType.Equal:
  82. return " =";
  83. case ExpressionType.GreaterThan:
  84. return " >";
  85. case ExpressionType.GreaterThanOrEqual:
  86. return ">=";
  87. case ExpressionType.LessThan:
  88. return "<";
  89. case ExpressionType.LessThanOrEqual:
  90. return "<=";
  91. case ExpressionType.NotEqual:
  92. return "<>";
  93. case ExpressionType.Or:
  94. case ExpressionType.OrElse:
  95. return " Or ";
  96. case ExpressionType.Add:
  97. case ExpressionType.AddChecked:
  98. return "+";
  99. case ExpressionType.Subtract:
  100. case ExpressionType.SubtractChecked:
  101. return "-";
  102. case ExpressionType.Divide:
  103. return "/";
  104. case ExpressionType.Multiply:
  105. case ExpressionType.MultiplyChecked:
  106. return "*";
  107. default:
  108. return null;
  109. }
  110. }

  

到这里,一个基于表达式分析的实体查询就做好了。

下面是文章一开始的那个lambda表达式分析出来的对应的where语句

对应的参数和参数值顺序是一一对应的。

我这里的对Expression表达式进行了计算,所以最后一个参数对应的

  1. string.Concat(GetStr(7), "sdfsdf".Length, "sssss" + GetStr(6)).ToUpper()

这个表达式已经被计算完成得到"GOOD76SSSSSGOOD6",GetStr(int)函数见第一张截图。

这里主要体会的是用Expression Tree的一个实际用法。实际跑起来体会下就能明白。要说的话实在内容太多。而前面的都介绍都是概念性的.

代码下载地址:http://download.csdn.net/detail/ysq5202121/4263117

用lambda构建ORM查询语句的更多相关文章

  1. hisql ORM 查询语句使用教程

    HiSql 提供一个可以适合多种数据库的中间查询语法,不需要关注各个数据库的语法特性,通过HiSql写语句可以在常用的不同类型数据库中执行,且语法与Sql语境类似一看就懂一学就会 hisql.net ...

  2. SpringBoot使用注解的方式构建Elasticsearch查询语句,实现多条件的复杂查询

    背景&痛点 通过ES进行查询,如果需要新增查询条件,则每次都需要进行硬编码,然后实现对应的查询功能.这样不仅开发工作量大,而且如果有多个不同的索引对象需要进行同样的查询,则需要开发多次,代码复 ...

  3. ORM查询条件

    模板: from django.db import models class Article(models.Model): title = models.CharField(max_length=20 ...

  4. Django(17)orm查询操作

    前言 查找是数据库操作中一个非常重要的技术.查询一般就是使用filter.exclude以及get三个方法来实现.我们可以在调用这些方法的时候传递不同的参数来实现查询需求.在ORM层面,这些查询条件都 ...

  5. ORM开发之解析lambda实现group查询(附测试例子)

    目的:以编程方式实现group查询,在开发ORM时,需要达到这样的效果 先看一个简单的group语句 select BarCode,ProductName,COUNT(BarCode) as tota ...

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

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

  7. 浅谈sql 、linq、lambda 查询语句的区别

    浅谈sql .linq.lambda 查询语句的区别 LINQ的书写格式如下: from 临时变量 in 集合对象或数据库对象 where 条件表达式 [order by条件] select 临时变量 ...

  8. 第二十篇ORM查询与SQL语句

    ORM查询与SQL语句 多表操作 创建模型 实例:我们来假定下面这些概念,字段和关系 作者模型:一个作者有姓名和年龄. 作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息.作者详情 ...

  9. Lambda表达式转SQL语句类库

    /* 作者:道法自然   * 个人邮件:myyangbin@sina.cn * 2014-10-1 */ Lambda表达式转SQL语句类库源码下载:http://download.csdn.net/ ...

随机推荐

  1. python 读写文本文件

    本人最近新学python ,用到文本文件的读取,经过一番研究,从网上查找资料,经过测试,总结了一下读取文本文件的方法. 1.在读取文本文件的时无非有两种方法: a.f=open('filename', ...

  2. linux删除某类型文件的命令

    使用linux命令行,删除某目录下某类型的文件,如:删除.rar结尾的所有文件. 命令如下: find . -name "*.rar" -type f -print -exec r ...

  3. 从某一日期开始过day天的日期

    一个SX问我的,我就写了写......从2010.1.1开始,给了一组测试数据3的话输出2010.1.4星期1,所以说2010.1.1是星期五,总星期就是 (day+5)%7==0?7:(day+5) ...

  4. 各大搜索引擎的User-Agent

    baidu:Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html) Google:Moz ...

  5. ListView 长按拖动会变黑的解决方案

    在ListView的xml文件中添加这个属性: android:cacheColorHint="#00000000"

  6. php smarty foreach循环注意

    在template中,要注意{foreach from=$arr item=value}其中的value不需要$美元符号

  7. code forces Jeff and Periods

    /* * c.cpp * * Created on: 2013-10-7 * Author: wangzhu */ #include<cstdio> #include<iostrea ...

  8. easyui源码翻译1.32--accordion(手风琴)

    前言 前几天加班比较忙 未能及时更新翻译的 今天多发布几篇..下载该插件翻译源码 Accordion 分类空间允许用户使用多面板,但在同一时间只会显示一个.每个面板都内建支持展开和折叠功能.点击一个面 ...

  9. 各种HTTP错误消息含义

    错误代码 错误消息 400 无法解析此请求. 401.1 未经授权:访问由于凭据无效被拒绝. 401.2 未经授权: 访问由于服务器配置倾向使用替代身份验证方法而被拒绝. 401.3 未经授权:访问由 ...

  10. 关于百度地图API的地图坐标转换问题

    原文:关于百度地图API的地图坐标转换问题 我在之前的文章利用html5获取经纬度并且在百度地图中显示位置中使用了百度地图的API来显示html5获取的地理位置,在文中我说过这样的话,我说百度地图的准 ...