回顧
上一篇我們根據工作單元的原理基于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的相關方法的。
結尾
到此資料層就隻差查詢了,下次會分享一下關于查詢的模式。
文章到這裡就結束了,如果有什麼問題和錯誤歡迎留言,謝謝!