昨天開源了業務業餘時間本身封裝的dapper lambda擴展,同時寫了篇博文《編寫本身的dapper lambda擴展-使用篇》簡單的介紹了下其使用,今天將分享下它的設計思路html
其實就是將多個方法經過點(.)將它們串接起來,讓代碼更加簡潔, 可讀性更強。node
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。git
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>(); } }
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); }
以上爲基本的設計模型,具體實現若有問題能夠查看個人源碼。github
具體實現的時候會涉及到不少的表達式樹的解析,例如where條件、部分字段update,而我實現的時候一共兩步:先修樹,再翻譯。然而不管哪步都得對錶達式樹進行遍歷。sql
百度的定義:也稱爲「表達式目錄樹」,以數據形式表示語言級代碼,它是一種抽象語法樹或者說是一種數據結構。編程
我對它的理解是,它本質是一個二叉樹,節點擁有本身的屬性像nodetype。數據結構
而它的遍歷方式爲前序遍歷app
百度的定義:歷首先訪問根結點而後遍歷左子樹,最後遍歷右子樹。在遍歷左、右子樹時,仍然先訪問根結點,而後遍歷左子樹,最後遍歷右子樹,如下圖爲例ide
其遍歷結果爲:ABDECFpost
以一個實際例子:
從上圖能夠看出,咱們會先遍歷到根節點的NodeType AndAlso翻譯爲 and ,而後到節點2,NodeType的Equal翻譯爲 = ,再到3節點翻譯爲 Name,再到4節點翻譯爲'skychen',那麼將三、4節點拼接起來就爲Name = 'skychen',若是類推六、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