在EF中,我们查询数据时可能会用拉姆达表达式 Where(Func<T,ture> func)这个方法来筛选数据,例如,我们定义一个User实体类

public class User
{
public Guid Id { get; set; }
public string LoginId { get; set; }
public string Name { get; set; }
public bool Enabled { get; set; }
public DateTime CreateTime { get; set; }
}

现在我想查询用户Enabled为true 并且Name 中包含'lilei'的用户,在EF中我们可能会这样去写:

XXX.Where(u => u.Name.Contains("lilei") && u.Enabled==true)

那么现在我想将Where方法中的那个泛型委托翻译成Sql语句中的一部分应该怎么做呢?下面是我已经写好的一个解析表达式的类,可能写得不是很规范,大家尽量吐槽:

using LC.Factory.Code;
using LC.Factory.Entity;
using LC.Factory.Resource;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;

namespace LC.Factory.Common
{
public class ExpressionAnalyzer
{
/// <summary>
/// 表达式所有参数集合
/// </summary>
private Dictionary<string, object> _params;
/// <summary>
/// 命名参数别名
/// </summary>
private const string _argName = "TAB";
/// <summary>
/// 解析结果
/// </summary>
public AnalysisData ResultData { get; set; }
public ExpressionAnalyzer()
{
ResultData = new AnalysisData();
_params = new Dictionary<string, object>();

}
public ExpressionAnalyzer(LambdaExpression exp)
: this()
{
if (exp != null)
{
AppendParams(GetChildValue(exp.Body), _params);
foreach (var item in exp.Parameters)
{
AnalysisTables(item);
}
AnalysisExpression(exp.Body, true);
}
}
/// <summary>
/// 解析表达式
/// </summary>
/// <param name="exp"></param>
/// <param name="isLeftChild"></param>
private void AnalysisExpression(Expression exp, bool isLeftChild = true)
{
switch (exp.NodeType)
{
case ExpressionType.AndAlso:
ResultData.StackList.Add("(");
AnalysisExpression(GetChildExpression(exp));
ResultData.StackList.Add(")");
ResultData.StackList.Add("AND");
ResultData.StackList.Add("(");
AnalysisExpression(GetChildExpression(exp, false), false);
ResultData.StackList.Add(")");
break;
case ExpressionType.OrElse:
ResultData.StackList.Add("(");
AnalysisExpression(GetChildExpression(exp));
ResultData.StackList.Add(")");
ResultData.StackList.Add("OR");
ResultData.StackList.Add("(");
AnalysisExpression(GetChildExpression(exp, false), false);
ResultData.StackList.Add(")");
break;
case ExpressionType.Equal:
AnalysisExpression(GetChildExpression(exp));
ResultData.StackList.Add("=");
AnalysisExpression(GetChildExpression(exp, false), false);
break;
case ExpressionType.NotEqual:
AnalysisExpression(GetChildExpression(exp));
ResultData.StackList.Add("!=");
AnalysisExpression(GetChildExpression(exp, false), false);
break;
case ExpressionType.GreaterThanOrEqual:
AnalysisExpression(GetChildExpression(exp));
ResultData.StackList.Add(">=");
AnalysisExpression(GetChildExpression(exp, false), false);
break;
case ExpressionType.GreaterThan:
AnalysisExpression(GetChildExpression(exp));
ResultData.StackList.Add(">");
AnalysisExpression(GetChildExpression(exp, false), false);
break;
case ExpressionType.LessThan:
AnalysisExpression(GetChildExpression(exp));
ResultData.StackList.Add("<");
AnalysisExpression(GetChildExpression(exp, false), false);
break;
case ExpressionType.LessThanOrEqual:
AnalysisExpression(GetChildExpression(exp));
ResultData.StackList.Add("<=");
AnalysisExpression(GetChildExpression(exp, false), false);
break;
case ExpressionType.Call:
var imExp = exp as MethodCallExpression;
AnalysisExpression(imExp.Object, true);
ResultData.StackList.Add("LIKE");
if (imExp.Arguments.Count > 0)
{
var arg0 = imExp.Arguments[0] as MemberExpression;
ResultData.StackList.Add("'%'+");
AnalysisExpression(imExp.Arguments[0], false);
ResultData.StackList.Add("+'%'");
}
break;
case ExpressionType.MemberAccess:
if (isLeftChild)
{
AnalysisTables(exp);
var mberExp = exp as MemberExpression;
var parentName = GetExpressionName(mberExp.Expression);
if (!string.IsNullOrEmpty(parentName))
{
ResultData.StackList.Add(string.Format("[{0}].{1}", parentName, GetExpressionName(exp)));
break;
}
ResultData.StackList.Add(GetExpressionName(exp));
}
else
{
var paramName = GetParamName(exp);
ResultData.ParamList.Add(paramName, _params[paramName]);
ResultData.StackList.Add(paramName);
}
break;
case ExpressionType.Constant:
var constent = exp as ConstantExpression;
if (constent.Value == null)
{
var op = ResultData.StackList.ElementAt(ResultData.StackList.Count - 1);
ResultData.StackList.RemoveAt(ResultData.StackList.Count - 1);
if (string.Equals(op, "="))
{
ResultData.StackList.Add("IS NULL");
}
else
{
ResultData.StackList.Add("IS NOT NULL");
}
break;
}
if (constent.Value.GetType() == typeof(String))
{
ResultData.StackList.Add(string.Format("'{0}'", constent.Value));
break;
}
if (constent.Value.GetType() == typeof(bool))
{
if (ResultData.StackList.Count > 0)
{
var value = Convert.ToBoolean(constent.Value);
ResultData.StackList.Add(string.Format("{0}", value ? "1" : "0"));
}

break;
}
ResultData.StackList.Add(string.Format("{0}", constent.Value));
break;
case ExpressionType.Convert:
var uExp = exp as UnaryExpression;
AnalysisExpression(uExp.Operand, isLeftChild);
break;
case ExpressionType.New:
var newExp = exp as NewExpression;
//解析查询字段
for (int i = 0; i < newExp.Arguments.Count; i++)
{
AnalysisExpression(newExp.Arguments[i]);
ResultData.StackList.Add("AS");
ResultData.StackList.Add(string.Format("'{0}'", newExp.Members[i].Name));
}
break;
case ExpressionType.Parameter:
throw new BusinessException(BusinessRes.SelectObjectMastBeAnNewObject);
//AnalysisExpression(Expression.New(exp.Type));
//break;
default:
break;
}

}
/// <summary>
/// 获取孩子节点
/// </summary>
/// <param name="exp"></param>
/// <param name="getLeft"></param>
/// <returns></returns>
private Expression GetChildExpression(Expression exp, bool getLeft = true)
{
var className = exp.GetType().Name;
switch (className)
{
case "BinaryExpression":
case "LogicalBinaryExpression":
var bExp = exp as BinaryExpression;
return getLeft ? bExp.Left : bExp.Right;
case "PropertyExpression":
case "FieldExpression":
var mberExp = exp as MemberExpression;
return mberExp;
case "MethodBinaryExpression":
var mbExp = exp as BinaryExpression;
return getLeft ? mbExp.Left : mbExp.Right;
case "UnaryExpression":
var unaryExp = exp as UnaryExpression;
return unaryExp;
case "ConstantExpression":
var cExp = exp as ConstantExpression;
return cExp;
case "InstanceMethodCallExpressionN":
var imExp = exp as MethodCallExpression;
return imExp;
default:
return null;
}
}
/// <summary>
/// 获取变量名
/// </summary>
/// <param name="exp"></param>
/// <param name="isLeftChild"></param>
/// <returns></returns>
private string GetExpressionName(Expression exp)
{
var className = exp.GetType().Name;
switch (className)
{
case "PropertyExpression":
case "FieldExpression":
var mberExp = exp as MemberExpression;
return string.Format("{0}", mberExp.Member.Name);
case "TypedParameterExpression":
return _argName;
default:
return string.Empty;
}
}
/// <summary>
/// 获取参数名
/// </summary>
/// <param name="exp"></param>
/// <param name="isLeftChild"></param>
/// <returns></returns>
private string GetParamName(Expression exp)
{
var className = exp.GetType().Name;
switch (className)
{
case "PropertyExpression":
case "FieldExpression":
var mberExp = exp as MemberExpression;
return string.Format("@{0}", mberExp.Member.Name);
case "TypedParameterExpression":
var texp = exp as ParameterExpression;
return string.Format("@{0}", texp.Name);
default:
return string.Empty;
}
}
/// <summary>
/// 解析表信息
/// </summary>
/// <param name="exp"></param>
private void AnalysisTables(Expression exp)
{
var className = exp.GetType().Name;
switch (className)
{
case "PropertyExpression":
case "FieldExpression":
var mberExp = exp as MemberExpression;
if (!IsDefaultType(mberExp.Type))
{
if (!ResultData.TableList.ContainsKey(mberExp.Member.Name))
{
ResultData.TableList.Add(mberExp.Member.Name, new AnalysisTable()
{
Name = mberExp.Type.Name,
TableType = mberExp.Type,
IsMainTable = false
});
}
}
AnalysisTables(mberExp.Expression);
break;
case "TypedParameterExpression":
//命名参数表达式
var texp = exp as ParameterExpression;
if (!IsDefaultType(texp.Type))
{
if (!ResultData.TableList.ContainsKey(_argName))
{
ResultData.TableList.Add(_argName, new AnalysisTable()
{
Name = texp.Type.Name,
TableType = texp.Type,
IsMainTable = true
});
}
}
break;
default:
break;
}
}
/// <summary>
/// 解析获取表达式的值
/// </summary>
/// <param name="exp"></param>
/// <param name="leftChild"></param>
/// <returns></returns>
private object GetChildValue(Expression exp)
{
var className = exp.GetType().Name;
switch (className)
{
case "BinaryExpression":
case "LogicalBinaryExpression":
var lExp = exp as BinaryExpression;
var ret = GetChildValue(lExp.Left);
if (IsNullDefaultType(ret))
{
ret = GetChildValue(lExp.Right);
}
return ret;
case "MethodBinaryExpression":
var mbExp = exp as BinaryExpression;
var ret1 = GetChildValue(mbExp.Left);
if (IsNullDefaultType(ret1))
{
ret1 = GetChildValue(mbExp.Right);
}
return ret1;

case "PropertyExpression":
case "FieldExpression":
var mberExp = exp as MemberExpression;
return GetChildValue(mberExp.Expression);
case "ConstantExpression":
var cExp = exp as ConstantExpression;
return cExp.Value;
case "UnaryExpression":
var unaryExp = exp as UnaryExpression;
return GetChildValue(unaryExp.Operand);
case "InstanceMethodCallExpressionN":
var imExp = exp as MethodCallExpression;
if (imExp.Arguments.Count > 0)
{
return GetChildValue(imExp.Arguments[0]);
}
return null;
default:
return null;
}

}
/// <summary>
/// 初始化所有参数
/// </summary>
/// <param name="paramObj"></param>
private void AppendParams(object paramObj, Dictionary<string, object> _params)
{
if (IsNullDefaultType(paramObj))
{
return;
}
if (_params == null)
{
_params = new Dictionary<string, object>();
}
foreach (var item in paramObj.GetType().GetProperties())
{
if (IsDefaultType(item.PropertyType))
{
var value = item.GetValue(paramObj, null);
if (value != null)
{
_params.Add(string.Format("@{0}", item.Name), value);
}
continue;
}

AppendParams(item.GetValue(paramObj), _params);
}

foreach (var item in paramObj.GetType().GetFields())
{
if (IsDefaultType(item.FieldType))
{
var value = item.GetValue(paramObj);
if (value != null)
{
_params.Add(string.Format("@{0}", item.Name), value);
}
continue;
}
AppendParams(item.GetValue(paramObj), _params);
}
}
public Dictionary<string, object> GetParams(object paramObj)
{
Dictionary<string, object> dicParams = new Dictionary<string, object>();
AppendParams(paramObj, dicParams);
return dicParams;
}
/// <summary>
/// 判断是否是系统默认基本类型
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private bool IsNullDefaultType(object obj)
{
if (obj == null)
{
return true;
}
return IsDefaultType(obj.GetType());
}
private bool IsDefaultType(Type type)
{
string defaultType = @"String|Boolean|Double|Int32|Int64|Int16|Single|DateTime|Decimal|Char|Object|Guid";

Regex e = new Regex(defaultType, RegexOptions.IgnoreCase);
if (type.Name.ToLower().Contains("nullable"))
{
if (type.GenericTypeArguments.Count() > 0)
{
return e.IsMatch(type.GenericTypeArguments[0].Name);
}
}
return e.IsMatch(type.Name);
}
}
}

在这个类中主要的方法是AnalysisExpression(Expression exp, bool isLeftChild = true),次啊面我们来测试一下上面的那个表达式:

[TestMethod]
public void TestExpression()
{

Expression<Func<User, bool>> exp = u => u.Name.Contains("lilei") && u.Enabled == true;
var result = new ExpressionAnalyzer(exp).ResultData;

if (result.TableList.Count > 0)
{
foreach (var item in result.TableList)
{
Console.WriteLine("{0} AS {1}", item.Value.Name, item.Key);
}
}
Console.WriteLine("***************************************************");
if (result.StackList.Count > 0)
{
Console.WriteLine(string.Join(" ", result.StackList));
}
Console.WriteLine("***************************************************");
if (result.ParamList.Count > 0)
{
foreach (var item in result.ParamList)
{
Console.WriteLine("{0} {1}", item.Key, item.Value);
}
}
}

输出结果:

  

再测试带参数的查询:

[TestMethod]
public void TestExpression()
{
var keyWord = "lilei";
var enable = true;

Expression<Func<User, bool>> exp = u => u.Name.Contains(keyWord) && u.Enabled == enable;
var result = new ExpressionAnalyzer(exp).ResultData;

if (result.TableList.Count > 0)
{
foreach (var item in result.TableList)
{
Console.WriteLine("{0} AS {1}", item.Value.Name, item.Key);
}
}
Console.WriteLine("***************************************************");
if (result.StackList.Count > 0)
{
Console.WriteLine(string.Join(" ", result.StackList));
}
Console.WriteLine("***************************************************");
if (result.ParamList.Count > 0)
{
foreach (var item in result.ParamList)
{
Console.WriteLine("{0} {1}", item.Key, item.Value);
}
}
}

输出结果:

  以上是根据表达式树解析出来的Sql碎片,这为后续生成Sql语句奠定了基础。

http://www.cnblogs.com/lispring/p/5324348.html

自己动手写ORM(01):解析表达式树生成Sql碎片的更多相关文章

  1. 自己动手写ORM(02):Sql生成器实现

    上一节中鄙人通过解析表达式树生成Sql碎片,其中我也把解析表达式类代码贴了出来,文章发布之后我对ExpressionAnalyzer类做了些改动,下面我还会将代码贴出来,废话不多说,直接进入今天的主题 ...

  2. 自己动手写ORM的感受

    之前看到奋斗前辈和时不我待前辈的自己动手写ORM系列博客,感觉讲解的通俗易懂,清晰透彻.作为一个菜鸟,闲来也想着自己写一个ORM,一来加深自己对 ORM的理解,以求对EF,NHibernate等ROM ...

  3. (新)自己动手写ORM框架(1)-增删查改的使用

    之前写过一个系列文章自己动手写ORM框架,经过在多个项目的中的使用,对这套代码进行了许多改进,下面是使用方法: 新增学员信息代码预览: DBHelper db = DBHelper.getInstan ...

  4. 自己动手写ORM框架

    提起ORM框架,大家都很熟悉,网上流行的ORM框架有很多,其中出名的有一些,不出名的更是数不胜数. 下面是自己实现的一个简单的ORM框架,实现了常用的增删查改功能,供大家研究ORM实现原理. 功能描述 ...

  5. 自己动手写ORM

    http://blog.csdn.net/sundacheng1989/article/category/1350100

  6. 太实用了!自己动手写软件——SSH、FTP和SQL server的密码破解

    我们的密码破解工具一共分为如下六个部分,前面四个部分我们都有在之前的文章中介绍过了 用户图形界面——GUI编程 密码字典获取——Excel文件读取 数据库类——MySQL.Oracle和SQL ser ...

  7. Python - 动手写个ORM

    Python - 动手写个ORM 任务: 模拟简单的ORM - Object Relational Mapping 为model添加create方法 代码很简单,直接上 字段类型类 class Fie ...

  8. 为初学者写ORM,ORM的原理及测试案例

    提纲 一.什么是ORM.二.反射以及Attribute在ORM中的应用.三.创建一个数据库表和表对应的实体model.四.实体model如何映射出数据库表.五.组合ORM映射生成insert语句.六. ...

  9. 【原创】自己动手写工具----XSmartNote [Beta 2.0]

    一.前面的话 在上一篇自己动手写工具----XSmartNote中,我简单介绍了这个小玩意儿的大致界面和要实现的功能,看了一下园子里的评论,评价褒贬不一,有人说“现在那么多云笔记的工具”,“极简版ev ...

随机推荐

  1. PHP图片的类型将其自动编码成base64

    <!--根据图片的类型将其自动编码成base64--><html><head><?php$file="test.jpg";$type=ge ...

  2. DEDECMS之0day入侵总结

    1.查看dedecms最后升级版本:http://xxx.com/data/admin/ver.txt 2.利用网上公开之0day进行对应版本之入侵 ps:dedecms默认CMS后台:http:// ...

  3. javascript快速入门13--BOM——浏览器对象模型(Browser Object Model)

    什么是BOM? BOM是Browser Object Model的缩写,简称浏览器对象模型 BOM提供了独立于内容而与浏览器窗口进行交互的对象 由于BOM主要用于管理窗口与窗口之间的通讯,因此其核心对 ...

  4. LeetCode(28)Implement strStr()

    题目 Implement strStr(). Returns the index of the first occurrence of needle in haystack, or -1 if nee ...

  5. Elasticsearch 理解

    概述 Elasticsearch (ES)是一个基于 Lucene 的开源搜索引擎,它不但稳定.可靠.快速,而且也具有良好的水平扩展能力,是专门为分布式环境设计的. 特性 安装方便:没有其他依赖,下载 ...

  6. @Autowired与@Resource的使用方法和差别

    一.@Autowired: 1.Spring 2.5 引入了 @Autowired 凝视,它能够对类成员变量.方法及构造函数进行标注,完毕自己主动装配的工作. 通过 @Autowired的使用来消除 ...

  7. Joomla详细安装图文教程

    Joomla 详细安装图文教程 第一步,配置网站信息 配置数据库:这里我选择MySQLi,可以根据自己的选择         安装-- 安装完成!

  8. iOS学习笔记-自己动手写RESideMenu

    代码地址如下:http://www.demodashi.com/demo/11683.html 很多app都实现了类似RESideMenu的效果,RESideMenu是Github上面一个stars数 ...

  9. 灰色预测--matlab&python实现

    function SGrey X0 = input('请输入原始负荷数据:'); %输入原始数据 n = length(X0); %原始n年数据 %累加生成 X1 = zeros(1,n); for ...

  10. \r与\n有何差别,编码的时候应该怎样使用

    差别: \r: 全称:carriage return (carriage是"字车"的意思.打印机上的一个部件) 简称:return 缩写:r ASCII码:13 作用:把光标移动到 ...