封裝自己的dapper lambda擴展-設計篇


前言

昨天開源了業務業余時間自己封裝的dapper lambda擴展,同時寫了篇博文編寫自己的dapper lambda擴展-使用篇簡單的介紹了下其使用,今天將分享下它的設計思路

鏈式編程

其實就是將多個方法通過點(.)將它們串接起來,讓代碼更加簡潔, 可讀性更強。

 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM