PetaPoco是一個輕量級ORM,我的MVC項目中使用它結合Repository模式,依靠Unity的生命周期管理對象,保證請求/線程級別的數據上下文單例,並使用鎖和計數實現業務級事務。下文代碼依個人理解實現,謬誤請不吝指正。
例行IUnitOfWork:
public interface IUnitOfWork { void Begin(); void Commit(); void Rollback(); }
倉庫上下文核心:
1 public class PetaPocoUnitOfWork : IUnitOfWork 2 { 3 private const String _dbName = "Northwind"; 4 private Boolean _requireAbort = false; 5 private Int32 _transactionDepth = 0; 6 private Object _transactionLock = new Object(); 7 8 public Database DBContext { get; protected set; } 9 10 public Guid Id { get; private set; } 11 12 public PetaPocoUnitOfWork() 13 { 14 Id = Guid.NewGuid(); 15 DBContext = new Database(_dbName); 16 } 17 18 public void Begin() 19 { 20 lock (_transactionLock) 21 { 22 if (_transactionDepth == 0) 23 { 24 DBContext.BeginTransaction(); 25 } 26 _transactionDepth++; 27 } 28 29 } 30 31 public void Commit() 32 { 33 lock (_transactionLock) 34 { 35 _transactionDepth--; 36 if (_transactionDepth == 0) 37 { 38 try 39 { 40 DBContext.CompleteTransaction(); 41 } 42 catch 43 { 44 _transactionDepth++; 45 _requireAbort = true; 46 throw; 47 } 48 } 49 } 50 } 51 52 public void Rollback() 53 { 54 lock (_transactionLock) 55 { 56 _transactionDepth--; 57 if (_transactionDepth == 0) 58 { 59 DBContext.AbortTransaction(); 60 _requireAbort = false; 61 } 62 } 63 } 64 65 public void Dispose() 66 { 67 if (_requireAbort) 68 { 69 DBContext.AbortTransaction(); 70 } 71 DBContext.Dispose(); 72 } 73 }
在應用層對Unity注入的IUnitOfWork調用Begin()即開啟事務,對於嵌套事務變量_transactionDepth++記錄事務深度,Commit()與Rollback()時_transactionDepth--,保證業務中事務只開啟與提交一次。如有應用層ITradeService及實現:
1 public abstract class ApplicationService { 2 public IUnitOfWork Context { get; private set; } 3 4 public ApplicationService(IUnitOfWork context) { 5 Context = context; 6 } 7 } 8 9 public interface ITradeService { 10 void SubmitOrder(Order model); 11 } 12 13 public class TradeService : ApplicationService, ITradeService { 14 private readonly IOrderRepository _orderRepository; 15 private readonly IOrderDetailRepository _orderDetailRepository; 16 17 public TradeService( 18 IUnitOfWork context, 19 IOrderRepository orderRepository, 20 IOrderDetailRepository orderDetailRepository) 21 : base(context) { 22 _orderRepository = orderRepository; 23 _orderDetailRepository = orderDetailRepository; 24 } 25 26 void SubmitOrder(OrderDTO model){ 27 //do something, like null reference check etc.. 28 29 Order order = //... some logic 30 OrderDetail orderDetail = //as above 31 32 try { 33 Context.Begin(); 34 35 _orderRepository.Update(order); 36 _orderDetailRepository.Update(orderDetail); 37 //could be more complex 38 39 Context.Commit(); 40 } 41 catch { 42 Context.Rollback(); 43 throw; 44 } 45 } 46 }
當顧客提交訂單時,Context.Begin()開啟一個事務鎖,由於Unity的生命周期管理,當前線程內的數據上下文實例是同一個對象,故能夠保證事務。當事務發生嵌套時,事務深度的解決方法發生作用,比如以可測試性的提高截取部分代碼示例:
[TestClass] public class AccountServiceTest { [TestMethod] public void TradeServiceTest_SubmitOrder() { IUnitOfWork context = ... //some initialize logic OrderDTO model = ... //as above TradeService service = //as above context.Begin(); service.SubmitOrder(); context.Rollback(); ///... etc } }
