前言

昨天开源了业务业余时间自己封装的dapper lambda扩展,同时写了篇博文《编写自己的dapper lambda扩展-使用篇》
<https://www.cnblogs.com/skychen1218/p/9229669.html>简单的介绍了下其使用,今天将分享下它的设计思路

链式编程

其实就是将多个方法通过点(.)将它们串接起来,让代码更加简洁, 可读性更强。
new SqlConnection("").QuerySet<User>() .Where(a => a.Name == "aasdasd")
.OrderBy(a=> a.CreateTime)
             .Top(10) .Select(a => a.Name).ToList();
 

其原理是类的调用方法的返回值类型为类本身或其基类,选择返回基类的原因是为了做降级约束,例如我希望使用了Top之后接着Select
和ToList,无法再用where或orderBy。

UML图



原型代码

CommandSet
public class CommandSet<T> : IInsert<T>, ICommand<T> { #region 方法 public int
Insert(T entity) {throw new NotImplementedException(); } public int Update(T
entity) {throw new NotImplementedException(); } public int
Update(Expression<Func<T, T>> updateExpression) { throw new
NotImplementedException(); }public int Delete() { throw new
NotImplementedException(); }public IInsert<T> IfNotExists(Expression<Func<T,
bool>> predicate) { throw new NotImplementedException(); } public ICommand<T>
Where(Expression<Func<T,bool>> predicate) { throw new
NotImplementedException(); }#endregion } public interface ICommand<T> { int
Update(T entity);int Update(Expression<Func<T, T>> updateExpression); int
Delete(); }public interface IInsert<T> { int Insert(T entity); } public static
class Database { public static QuerySet<T> QuerySet<T>(this SqlConnection
sqlConnection) {return new QuerySet<T>(); } public static CommandSet<T>
CommandSet<T>(this SqlConnection sqlConnection) { return new CommandSet<T>(); }
} View Code
 

QuerySet
public class QuerySet<T> : IAggregation<T> { #region 方法 public T Get() { throw
new NotImplementedException(); } public List<T> ToList() { throw new
NotImplementedException(); }public PageList<T> PageList(int pageIndex, int
pageSize) {throw new NotImplementedException(); } public List<T>
UpdateSelect(Expression<Func<T, T>> @where) { throw new
NotImplementedException(); }public IQuery<TResult>
Select<TResult>(Expression<Func<T, TResult>> selector) { throw new
NotImplementedException(); }public IOption<T> Top(int num) { throw new
NotImplementedException(); }public IOrder<T>
OrderBy<TProperty>(Expression<Func<T, TProperty>> field) { throw new
NotImplementedException(); }public IOrder<T>
OrderByDescing<TProperty>(Expression<Func<T, TProperty>> field) { throw new
NotImplementedException(); }public int Count() { throw new
NotImplementedException(); }public bool Exists() { throw new
NotImplementedException(); }public QuerySet<T> Where(Expression<Func<T, bool>>
predicate) {throw new NotImplementedException(); } #endregion } public interface
IAggregation<T> : IOrder<T> { int Count(); bool Exists(); } public interface
IOrder<T> : IOption<T> { IOrder<T> OrderBy<TProperty>(Expression<Func<T,
TProperty>> field); IOrder<T> OrderByDescing<TProperty>(Expression<Func<T,
TProperty>> field); } public interface IOption<T> : IQuery<T>, IUpdateSelect<T>
{ IQuery<TResult> Select<TResult>(Expression<Func<T, TResult>> selector);
IOption<T> Top(int num); } public interface IUpdateSelect<T> { List<T>
UpdateSelect(Expression<Func<T, T>>where); } public interface IQuery<T> { T
Get(); List<T> ToList(); PageList<T> PageList(int pageIndex, int pageSize); }
View Code
 

以上为基本的设计模型,具体实现如有问题可以查看我的源码。

表达式树的解析


具体实现的时候会涉及到很多的表达式树的解析,例如where条件、部分字段update,而我实现的时候一共两步:先修树,再翻译。然而无论哪步都得对表达式树进行遍历。

表达式树

百度的定义:也称为“表达式目录树”,以数据形式表示语言级代码,它是一种抽象语法树或者说是一种数据结构。

我对它的理解是,它本质是一个二叉树,节点拥有自己的属性像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。

修树


修树的目的,为了我们更好的翻译,例如DateTime.Now表达式树里的NodeType为MemberAccess,我希望转换成NodeType为Constant类型,以'2018-06-27
16:18:00'这个值作为翻译。

结束

以上为设计和实现的要点,具体的实现问题可以查看源码,如果有建议和疑问可以在下方留言,如果对您起到作用,希望您点一下推荐作为对我的支持。

再次双手奉上源码:https://github.com/SkyChenSky/Sikiro.DapperLambdaExtension.MsSql

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信