昨天我把闲暇时打包的dapper lambda扩展开源了,并写了一篇博文《编写自己的dapper lambda扩展-使用篇》简单介绍了它的使用,今天分享一下它的设计思路
其实就是将多个方法通过点(.)串联起来,让代码更加简洁易读。
new SqlConnection("").QuerySet() .Where(a => www.gsm-guard.net == "aasdasd") .OrderBy(a => a.CreateTime)
.Top(10) .Select(a => www.gsm-guard.net).ToList();
原则是类的调用方法的返回值类型是类本身或其基类。选择返回基类的原因是为了做降级约束。比如我希望用After Top,然后Select和ToList,where或者orderBy就不能再用了。
公共 类CommandSet:IInsert 、ICommand { #地区方法 public int 插入(T 实体) { 抛出新NotImplementedException(); } public int更新(T实体) { 抛出新NotImplementedException(); } public int更新(表达式 >更新表达式) { 抛出新NotImplementedException(); } 公共 int删除() { 抛出新NotImplementedException(); } public IInsert IfNotExists(Expression bool>>谓词) { 抛出新NotImplementedException(); }public ICommand 其中(表达式 bool>> 谓词) { 抛出新NotImplementedException(); } #endregion } 公共 接口 ICommand { int更新(T实体); int更新(表达式 >更新表达式); int删除(); } 公共 接口 I插入 { int插入(T实体); } 公共 静态 类 数据库 { 公共 静态 查询集 查询集 (这个 Sq l连接sqlConnection) { returnnewQuerySet (); } 公共 静态CommandSet CommandSet (这个 SqlConnect ion sql连接) { 返回新命令集 (); } }
公共 类 查询集:IAggregation { #地区方法 公共 T Get() { 抛出新NotImplementedException(); } 公共列表 ToList() { 抛出新NotImplementedException(); } 公共页面列表 页面列表(int页面索引,int页面大小) { 抛出新NotImplementedException(); } 公共列表 UpdateSelect(表达式 >@where) { 抛出新NotImplementedException(); } public IQuery Select (表达式 >选择器) {抛出新NotImplementedException(); } 公共 IOption 顶部(int数字) { 抛出新NotImplementedException(); } public IOrder OrderBy (表达式 > 字段) { 抛出新NotImplementedException(); } public IOrder OrderByDescing (表达式 > 字段) { 抛出新NotImplementedException(); } 公共 int 计数() { 抛出新NotImplementedException(); } 公共布尔存在() { 抛出新NotImplementedException(); } public QuerySet 其中(表达式 bool>> 谓词) {抛出新NotImplementedException(); } #endregion } 公共 接口 IAggregation : IOrder { int计数(); 布尔存在(); } 公共 接口 IOrder : IOption { IOrder OrderBy (表达式 > 字段); IOrder OrderByDescing (表达式 > 字段); } 公共 接口 IOption : IQuery , IUpdateSelect { IQuery Select (表达式 >选择器); IOption 顶部(intnum); } 公共 接口 IUpdateSelect { 列表 UpdateSelect(表达式 > where); } 公共 接口 IQuery { 获取(); 列表 ToList();PageList PageList(int pageIndex, int pageSize); }
以上是基本设计模型。如果对具体实现有疑问,可以查看我的源码。
具体实现会涉及到很多表达式树的解析,比如where条件、部分字段更新等。我实现的时候有两个步骤:先修复树,然后翻译。然而,无论采取哪一步,都必须遍历表达式树。
百度的定义:又称“表达式目录树”,以数据的形式表示语言级别的代码。它是一个抽象语法树或数据结构。
我对它的理解是,它本质上是一棵二叉树,节点有自己的nodetype等属性。
并且其遍历方式为前序遍历
百度的定义:日历首先访问根节点,然后遍历左子树,最后遍历右子树。遍历左右子树时,仍然先访问根节点,然后遍历左子树,最后遍历右子树。下图为示例
遍历结果为:ABDECF
举个实际例子:
从上图可以看出,我们会先遍历到根节点的NodeType AndAlso,翻译为and,然后到节点2,NodeType的Equal翻译为=,然后到节点3,它被翻译为Name,然后到节点4,它被翻译为'skychen',那么节点3和4的拼接将是Name = 'skychen'。如果类比节点6和7是Age >= 18,那么最终的拼接语句就是Name = 'skychen' and Age >= 18。
为了树修复的目的,为了我们更好的翻译,例如www.gsm-guard.net表达式树中的NodeType是MemberAccess。我希望将NodeType转换为Constant类型,以 '2018-06-27 16:18:00' 这个值作为翻译。
以上是设计和实现的要点。具体实现问题可以查看源码。如果您有建议和疑问,可以在下方留言。如果对你有用,希望你能点击推荐作为对我的支持。
再次双手提供源码:https://www.gsm-guard.net/SkyChenSky/Sikiro.DapperLambdaExtension.MsSql