有话说

之前我写了3篇关于表达式树解析的文章

干货!表达式树解析"框架"(1)

干货!表达式树解析"框架"(2)

干货!表达式树解析"框架"(3) 

这3篇文章更多的是说明一种方法,一种思路,而代码比较少

在发出来之后也有些朋友互加了好友一起讨论

在经过一些时间的修改和优化后,就有了现在这个框架

目前这个框架实现了SqlServer和Oracle的解释

其他数据库1来是不熟2来没时间3来我更希望大家可以使用这个框架自己动手实现一个数据库的解析,非常有意思

特色

  1. 首先是这个框架的名字 : Faller 中译 伐木工,但我喜欢叫他 "砍树人",因为他把"表达式树"这颗大树砍成一片一片的小块然后转化成sql语句
  2. 轻量 : 不仅仅是代码轻量,重新实现对一个新的数据库支持也很轻量,只需要实现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 == ''

     

  3. 灵活 : 在轻量的基础上尽量做到了灵活,可以非常方便的解析各种C#的方法

  4. 对 DateTime.Now 的处理 : 
    如 :  Where(u => u.Birthday < DateTime.Now) //可以被解析为 BIRTHDAY < SYSDATE 或 BIRTHDAY < GETDATE() 
  5. 自由的 SqlExpr : 有时候 我们不得不使用Sql来表示某个数据库特有的数据
    如 :  Set<User>(() => new User{ ID = (SqlExpr)"seq_user.nextval"}) //解析后得到 ID = seq_user.nextval 
  6. 使用方便 : 可以非常方便的嵌入到现已有的项目中,主要根据自己项目的需求重新实现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; }
}
IFaller

相关文章: