有话说
之前我写了3篇关于表达式树解析的文章
这3篇文章更多的是说明一种方法,一种思路,而代码比较少
在发出来之后也有些朋友互加了好友一起讨论
在经过一些时间的修改和优化后,就有了现在这个框架
目前这个框架实现了SqlServer和Oracle的解释
其他数据库1来是不熟2来没时间3来我更希望大家可以使用这个框架自己动手实现一个数据库的解析,非常有意思
特色
- 首先是这个框架的名字 : Faller 中译 伐木工,但我喜欢叫他 "砍树人",因为他把"表达式树"这颗大树砍成一片一片的小块然后转化成sql语句
- 轻量 : 不仅仅是代码轻量,重新实现对一个新的数据库支持也很轻量,只需要实现ISaw接口,或继承BaseSaw实现少量方法即可
如 :Where(u => u.Birthday.Day == 1); //EXTRACT(DAY FROM a.BIRTHDAY) = 1 Where(u => u.Name.Trim() == ""); //ltrim(rtrim(a.NAME)) = :auto_p0 Where(u => string.IsNullOrEmpty(u.Name)); //a.NAME IS NULL OR a.NAME == ''
-
灵活 : 在轻量的基础上尽量做到了灵活,可以非常方便的解析各种C#的方法
- 对 DateTime.Now 的处理 :
如 : Where(u => u.Birthday < DateTime.Now) //可以被解析为 BIRTHDAY < SYSDATE 或 BIRTHDAY < GETDATE() - 自由的 SqlExpr : 有时候 我们不得不使用Sql来表示某个数据库特有的数据
如 : Set<User>(() => new User{ ID = (SqlExpr)"seq_user.nextval"}) //解析后得到 ID = seq_user.nextval - 使用方便 : 可以非常方便的嵌入到现已有的项目中,主要根据自己项目的需求重新实现ISaw即可
使用方式
void Where(string expected, Expression<Func<User, bool>> expr) { var parse = Faller.Create(expr); //通过LambdaExpression创建Faller对象 var sql = parse.ToWhere(OracleSaw.Instance);//使用特定的ISaw来格式化Sql语句 //parse.Parameters //解析过程中产生的参数 Assert.AreEqual(expected, sql); }
项目结构
- Faller : 解析框架主要功能类,不可重写,实现 IFaller 接口,主要方法有 public static IFaller Create(LambdaExpression expr)
- ISaw : 定义一组方法,它支持自定义Sql语句的格式。Faller负责拆解 LambdaExpression ,然后把特定的对象交给ISaw处理返回sql语句
- SawDust : 解析结果。当一个方法在Faller中无法被解释时候,Faller会把方法所用到的对象和参数都构造成为SawDust 并交给ISaw处理,SawDust 由DustType Type和Object Value组成
- DustType : 表示解释结果类型的枚举 ,它的值有 Undefined, Sql, Object, Number, Array, Boolean, DateTime, Binary, String
-
SqlExpr : Sql表达式,它只能由String强转获得; 它可以隐式转换为所有基础对象,但只能在表达式树中使用, 如
Where<User>(u => (SqlExpr)"@@identity" == 5); //@@identity = 5
对象定义
// 轻量级表达式树解析器 接口 public interface IFaller { // 将表达式转为Where语句,不包含Where关键字 //saw: 自定义输出Sql语句的格式的对象 string ToWhere(ISaw saw); // 将表达式转为OrderBy语句,不包含OrderBy关键字 //saw: 自定义输出Sql语句的格式的对象 //asc: 正序或倒序标识 string ToOrderBy(ISaw saw, bool asc); // 将表达式转为Update中Set语句,不包含Set关键字 //saw: 自定义输出Sql语句的格式的对象 string ToSets(ISaw saw); // 将表达式转为select语句中的列或列集合的Sql语句 //saw: 自定义输出Sql语句的格式的对象 string ToSelectColumns(ISaw saw); // 将表达式转为值或值集合的sql语句 //saw: 自定义输出Sql语句的格式的对象 string ToValues(ISaw saw); // 将表达式转为值或值集合的sql语句 //saw: 自定义输出Sql语句的格式的对象 string ToValues(ISaw saw, Func<string, string> replace); // 将表达式转为列集合和值集合2个sql语句,可用于拼装insert语句 //saw: 自定义输出Sql语句的格式的对象 KeyValuePair<string, string> ToColumnsAndValues(ISaw saw); // 转换Sql语句过程中产生的参数 ICollection<DbParameter> Parameters { get; } }