天天看點

Unit Of Work--工作單元(二)

回顧

  上一篇我們根據工作單元的原理基于ADO.NET進行了簡單的實作,但是當項目需求發生變化的時候,比如需要引入ORM架構又要相容目前ADO.NET實作的方式時,先前的實作就無法滿足這個需求了。

  話就不多說了,我們就跟據目前的需求變化來重構工作單元吧。

重構UnitOfWork

  首先我們看看原先實作的工作單元提取出來的接口,代碼如下:

public interface IUnitOfWork
{
    void RegisterAdd(string sql, params IDataParameter[] parameters);                             
    void RegisterSave(string sql, params IDataParameter[] parameters);                           
    void RegisterRemove(string sql, params IDataParameter[] parameters);                          
    void Comit();
}      

  由于需求需要相容ORM和ADO.NET方式,而以上的接口僅僅支援ADO.NET的方式,是以接口需要改變,例如:

//其他代碼省略
void RegisterAdd(object entity);
      

  觀察以上的修改會發現如果要滿足需求,則需要判斷是ADO.NET或者是ORM的操作,那麼就有了兩種不同的職責,這顯然是不合理的,但是如果我們将ADO.NET和ORM還是讓對應的資料層類去實作的話,就符合單一責任了,于是經過以上分析,就可以對以上的接口做進一步的修改了,大緻代碼如下:

//其他代碼省略
void RegisterAdd(object entity, IUnitOfWorkRepository repository);
      

  按照這個思路的話,這個IUnitOfWorkRepository的方法數量則會跟IUnitOfWork基本相同(沒有Commit),一個是注冊,而另一個則是實際的操作,是以接口代碼則會跟第一次改為object的相同了,代碼如下:

public interface IUnitOfWorkRepository
{
    void ExecuteAdd(object entity);                             
    void ExecuteSave(object entity);                           
    void ExecuteRemove(object entity);
}      

  有了以上的改變之後,就可以實作IUnitOfWork了,代碼結構上還是跟SQLUnitOfWork類似的,差别是原先是使用一個List<SQLEntity>來存儲所有的CUD操作,但是現在必須要區分出不同類型的操作,是以需要有分别存儲CUD的容器,大緻代碼如下:

public class UnitOfWork : IUnitOfWork
{
    private Dictionary<object, IUnitOfWorkRepository> m_addList = 
        new Dictionary<object, IUnitOfWorkRepository>();
    private Dictionary<object, IUnitOfWorkRepository> m_saveList =
        new Dictionary<object, IUnitOfWorkRepository>();
    private Dictionary<object, IUnitOfWorkRepository> m_removeList = 
        new Dictionary<object, IUnitOfWorkRepository>();

    public void RegisterAdd(object entity, IUnitOfWorkRepository repository)
    {
        if (!this.m_addList.ContainsKey(entity))
            this.m_addList.Add(entity, repository);
    }

    public void RegisterSave(object entity, IUnitOfWorkRepository repository)
    {
        if (!this.m_saveList.ContainsKey(entity))
            this.m_saveList.Add(entity, repository);
    }

    public void RegisterRemove(object entity, IUnitOfWorkRepository repository)
    {
        if (!this.m_removeList.ContainsKey(entity))
            this.m_removeList.Add(entity, repository);
    }

    public void Commit()
    {
        using (TransactionScope trans = new TransactionScope())
        {
            foreach (var entity in this.m_addList.Keys)
            {
                this.m_addList[entity].ExecuteAdd(entity);
            }

            foreach (var entity in this.m_saveList.Keys)
            {
                this.m_saveList[entity].ExecuteSave(entity);
            }

            foreach (var entity in this.m_removeList.Keys)
            {
                this.m_removeList[entity].ExecuteRemove(entity);
            }
            trans.Complete();
        }
    }
}
      

  到這裡我們就将工作單元重構工作完成了,接下來就可以根據IUnitOfWorkRepository派生出基于ADO.NET和ORM的實作了。

重構SchoolRepository

  首先我們先看一下重構後的代碼:

class SchoolRepository : IRepository, IUnitOfWorkRepository
{
    private IDbConnection m_connection = null;
    private IUnitOfWork m_uow = null;

    public SchoolRepository(IDbConnection connection, IUnitOfWork uow)
    {
        this.m_connection = connection;
        this.m_uow = uow;
    }

    public void Add(object entity)
    {
        this.m_uow.RegisterAdd(entity, this);
    }

    public void Save(object entity)
    {
        this.m_uow.RegisterSave(entity, this);
    }

    public void Remove(object entity)
    {
        this.m_uow.RegisterRemove(entity, this);
    }

    public void ExecuteAdd(object entity)
    {
        School school = entity as School;
        using (IDbCommand cmd = this.m_connection.CreateCommand())
        {
            cmd.CommandType = CommandType.Text;
            cmd.CommandText = "insert school values(@id, @name)";
            cmd.Parameters.Add(new SqlParameter("@id", school.Id));
            cmd.Parameters.Add(new SqlParameter("@name", school.Name));
            cmd.ExecuteNonQuery();
        }
    }

    public void ExecuteSave(object entity)
    {
        //代碼略
    }

    public void ExecuteRemove(object entity)
    {
        //代碼略
    }
}
      

  IRepository是資料層的基礎接口,從代碼中我們看到原先CUD的方法被拆分到了CUD和ExecuteXXX方法中去了,CUD方法負責調用IUnitOfWork的接口,而ExecuteXXX則實作具體的資料庫操作

基于NHibernate的IUnitOfWorkRepository實作

  先看代碼吧

class SchoolRepository : IRepository, IUnitOfWorkRepository
{
    private IUnitOfWork m_uow = null;

    public SchoolRepository(IDbConnection connection, IUnitOfWork uow)
    {
        this.m_uow = uow;
    }

    public void Add(object entity)
    {
        this.m_uow.RegisterAdd(entity, this);
    }

    public void Save(object entity)
    {
        this.m_uow.RegisterSave(entity, this);
    }

    public void Remove(object entity)
    {
        this.m_uow.RegisterRemove(entity, this);
    }

    public void ExecuteAdd(object entity)
    {
        SessionFactory.CurrentSession.Add(entity);
    }

    public void ExecuteSave(object entity)
    {
        //代碼略
    }

    public void ExecuteRemove(object entity)
    {
        //代碼略
    }
}
      

  從基于NHibernate的實作中,我們可以看到ExecuteXXX的方法都是去調用NHibernateSession的相關方法的。

結尾

  到此資料層就隻差查詢了,下次會分享一下關于查詢的模式。

  文章到這裡就結束了,如果有什麼問題和錯誤歡迎留言,謝謝!