我正在一個Web API項目(ninject,原始sql查詢,存儲庫模式,UoW模式)我已經檢查幾乎無處不在的一篇文章,將描述UoW的實現簡單的數據庫事務W/O使用實體框架(普通SQL請求和SqlConnection等等),但找不到任何東西。C#UnitOWork實現沒有EF與數據庫事務或TransactionScope
我遇到的問題是以下幾點。我有一個Web API,它有一些控制器與存儲庫一起工作,而這些控制器又通過DBManager類通過UoW注入到DB中。
讓我們想象一下我有2個方法,在一個倉庫,數據庫中的每個人的更新數據:
方法1 - 更新票(從客戶添加後)。方法2 - 更新故障單的狀態(僅在發佈成功後)。
這些方法可以被一個接一個地調用,或者單獨調用,也就是說,例如,在售票關閉之後,可以從某種其他方法調用Method2。
方法1在更新數據庫之前通過DBManager創建事務。然後它更新DB並調用Method2來完成他的工作。 Method2,因爲它也可以作爲一個獨立的方法調用,所以在更新數據庫之前也會啓動事務。當查詢被執行時,它提交事務並返回到Method1。此階段的Method1也提交事務,因爲沒有任何異常,它想要保留對數據庫所做的更改。但是,它不能因爲方法2已經做出了改變。
這樣的動作圖類似於一個下面的東西:
Method1()
DBManager.BeginTransaction() - begins new transaction
update DB - adds post to the ticket
Method2() - calls method 2 to update ticket status
DBManager.BeginTransaction() - returns transaction started by Method1()
update DB - updates ticket status
DBManager.CommitTransaction() - commits transaction
return
DBManager.CommitTransaction() - commits transaction to save ALL changes but can't since transaction was already committed.
如果我需要調用其他方法票狀態更新後,再方法將用全新的一組數據,因爲變化是工作由Method2()提交到DB中。
我開始思考如何解決這個問題,但找不到任何東西。我已閱讀有關的TransactionScope,我想我可以做這樣的事情:
public class UnitOfWork : IUnitOfWork, IDisposable
{
/// <summary>
/// DB context.
/// </summary>
private IDBManager _dbManager;
/// <summary>
/// Repository provider class which can create repositories on demand.
/// </summary>
private IRepositoryProvider _repositoryProvider;
private TransactionScope _transaction;
public UnitOfWork(IDBManager dbManager, IRepositoryProvider repoProvider)
{
_dbManager = dbManager;
_repositoryProvider = repoProvider;
}
public T GetRepository<T>()
{
if (_transaction == null)
_transaction = new TransactionScope();
return _repositoryProvider.Create<T>(_dbManager);
}
public void Save()
{
_transaction.Complete();
}
public void Dispose()
{
_transaction.Dispose();
}
}
在這種情況下,當我創建我的第一個存儲庫中的TransactionScope會開始,然後我可以調用保存在我的控制器,就像這樣:
public TicketPost AddTicketPost(int tid, TicketPost update)
{
TicketPost post = Uow.GetRepository<ITicketsRepository>().AddPost(tid, update);
Uow.Save();
return post;
}
但是,這意味着TransactionScope會爲任何操作創建 - 選擇/更新/刪除,它會持續從創建第一個存儲庫的時刻開始(即使我可能不需要它),直到交易處置或完成。
另一種解決方案是使用DBManager的事務,並在控制器中調用BeginTransaction並在需要時調用Commit或Rollback。像這樣:
Uow.BeginTransaction();
try
{
TicketPost post = Uow.GetRepository<ITicketsRepository>().AddPost(tid, update);
}
catch (Exception e)
{
Uow.RollbacTransaction();
}
Uow.CommitTransaction();
但我不太喜歡這種方法。在第一種情況下,我需要捕獲異常,這些異常會冒泡到我的ExceptionsHandler中,它會向客戶端創建響應消息。另外,我認爲一個控制器是一箇中間人,他會得到請求並說:「嘿,存儲庫,這裏是數據,我已經檢查過,做你的事情,然後給我回電話。」當它從存儲庫中獲得「調用」時,它可能會做一些與數據無關的事情,比如發送電子郵件。我喜歡當控制器不需要在同一個庫調用方法逐一認爲它需要做的,像完成任務的事情:
- 更新售票
- 將狀態設置
- 巨蛋別的東西與票
- 發送電子郵件
,而不是這個,控制器問庫照顧票更新和等待的同時,也可以發送電子郵件:
- 告訴控制器做他需要做的事情來更新票證。
- 等待併發送電子郵件。
我在踩踏控制器和存儲庫時可能會出錯。如果我錯了,請糾正我。
我希望有人能指點我一個資源,或者可能有人有類似的設置,並已經找到了解決方案(交易問題)。
任何幫助,將不勝感激。非常感謝你提前。
哇,太好了。非常感謝你的想法。這個想法是以某種方式強制所有更新/刪除操作在我認爲您的方法允許的同一個事務保護下工作。我也想問一下,在創建TransactionScope的過程中創建TransactionScope是否可行,在UoW中,然後讓它在那裏,打開,在我使用數據庫並執行其他活動的整個過程中都可以。或者有什麼我可能在這裏失蹤?當有一個TransactionScope打開時,可能某些操作可能會以不同的方式工作,而不僅僅是數據庫請求? –
我試圖想出一種使用你建議的方法。正如我所提到的,我使用Ninject。它將UoW注入到我的控制器中,然後使用它創建存儲庫。現在,而不是UoW我需要注入某種UoW工廠,通過它我將創建所需的UoW類型對象。我想 –
那麼,關於你的第一個評論,你必須明白,工作單元塊應儘可能快(小)。否則,你會開始有數據庫性能問題。 所以,當使用uow時,你應該儘量保持它很小。我將編輯答案,以作爲例證。 –