在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. WebLogic Server 多租户资源管理(resource consume manager)

    WebLogic Server基于分区管理heap Size,CPU利用率等,具体的设置如下, 首先需要在setDomainEnv.cmd文件中java_option中加入如下字段 -XX:+Unlo ...

  2. RDD编程 上(Spark自学三)

    弹性分布式数据集(简称RDD)是Spark对数据的核心抽象.RDD其实就是分布式的元素集合.在Spark中,对数据的操作不外乎创建RDD.转化已有RDD以及调用RDD操作进行求值.而在这一切背后,Sp ...

  3. ZOJ 3526 Weekend Party

    Weekend Party Time Limit: 2 Seconds      Memory Limit: 65536 KB As the only Oni (a kind of fabulous ...

  4. 使用Google-Authenticator加强serverSSH登录

    对于须要特殊加密的人群,我这里给出对应的方法来进行谷歌式加密. 过程例如以下: 准备: 首先在你的手机上准备好client(自己百度下载) 接下来依照命令做: date 查看系统时间       da ...

  5. Android调试方法总结

    Android程序调试过程中,通常需要在控制台或者AVD中弹出相关信息作为调试使用,以下是调试使用中会用到的Log类和Toast类的使用方法: 1.Toast Toast是在AVD上显示信息的一种机制 ...

  6. 阿里云OSS服务开通STS安全令牌

    搭建直传服务需要完成以下准备工作: 开通OSS,并且创建Bucket. 开通STS服务. 登录 OSS管理控制台. 在OSS概览页中找到基础配置区域,单击 安全令牌,如下图所示: 进入到 安全令牌快捷 ...

  7. MVC中上传文件大小限制的解决办法

    在Web.Config文件中配置限制上传文件大小与时间. 需要在配置文件里面设置文件上传限定的两个属性值:maxAllowedContentLength,maxRequestLength 允许上传文件 ...

  8. GBDT,随机森林

    author:yangjing ## time:2018-10-22 Gradient boosting decision tree 1.main diea The main idea behind ...

  9. tcp/ip ---数据封装过程

  10. MySQL Memory 存储引擎浅析

    原创文章,转载必需注明出处:http://www.cnblogs.com/wu-jian/ 前言 需求源自项目中的MemCache需求,開始想用MemCached(官方网站:http://memcac ...