如何使用存储库模式以事务方式封装多个实体的保存?例如,如果我想根据订单创建添加订单并更新客户状态,但只有在订单成功完成时才会这样做?请记住,对于此示例,订单不是客户内的集合.他们是自己的实体.
这只是一个人为的例子,所以我并不关心订单是否应该在客户对象内部,甚至不在同一个有限的上下文中.我真的不在乎将使用什么底层技术(nHibernate,EF,ADO.Net,Linq等).我只是想看看一些调用代码在这个公认的全有或全无操作示例中的样子.
今天早上启动我的电脑我遇到了我正在进行的项目的确切问题.我有一些想法导致以下设计 - 评论将超过令人敬畏.不幸的是,Josh建议的设计是不可能的,因为我必须使用远程SQL服务器并且无法启用它所依赖的Distribute Transaction Coordinator服务.
我的解决方案基于对现有代码的一些简单更改.
首先,我的所有存储库都实现了一个简单的标记接口:
////// A base interface for all repositories to implement. /// public interface IRepository { }
其次,我让所有启用事务的存储库实现以下接口:
////// Provides methods to enable transaction support. /// public interface IHasTransactions : IRepository { ////// Initiates a transaction scope. /// void BeginTransaction(); ////// Executes the transaction. /// void CommitTransaction(); }
我的想法是,在我的所有存储库中,我实现了这个接口,并添加了直接引入事务的代码,具体取决于实际的提供程序(对于伪造的存储库,我已经创建了一个在提交时执行的委托列表).对于LINQ to SQL,可以很容易地实现如下的实现:
#region IHasTransactions Members public void BeginTransaction() { _db.Transaction = _db.Connection.BeginTransaction(); } public void CommitTransaction() { _db.Transaction.Commit(); } #endregion
这当然要求为每个线程创建一个新的存储库类,但这对我的项目来说是合理的.
如果存储库实现,则使用存储库的每个方法都需要调用BeginTransaction()
和.为了使这个电话更容易,我提出了以下扩展:EndTransaction()
IHasTransactions
////// Extensions for spawning and subsequently executing a transaction. /// public static class TransactionExtensions { ////// Begins a transaction if the repository implements /// public static void BeginTransaction(this IRepository repository) { var transactionSupport = repository as IHasTransactions; if (transactionSupport != null) { transactionSupport.BeginTransaction(); } } public static void CommitTransaction(this IRepository repository) { var transactionSupport = repository as IHasTransactions; if (transactionSupport != null) { transactionSupport.CommitTransaction(); } } }. ///
评论赞赏!
我会看一下使用某种类型的Transaction Scope/Context系统.所以你可能有以下代码,大致基于.Net和C#.
public class OrderService { public void CreateNewOrder(Order order, Customer customer) { //Set up our transactional boundary. using (TransactionScope ts=new TransactionScope()) { IOrderRepository orderRepos=GetOrderRespository(); orderRepos.SaveNew(order); customer.Status=CustomerStatus.OrderPlaced; ICustomerRepository customerRepository=GetCustomerRepository(); customerRepository.Save(customer) ts.Commit(); } } }
TransactionScope可以嵌套,所以假设您有一个跨越多个服务的操作,您的应用程序也会创建一个TransactionScope.现在在当前的.net中,如果您使用TransactionScope,他们就有可能冒险进入DTC,但这将在未来得到解决.
我们创建了自己的TransactionScope类,它基本上管理了我们的数据库连接并使用了本地SQL事务.
使用Spring.NET AOP + NHibernate,您可以正常编写存储库类,并在自定义XML文件中配置事务:
public class CustomerService : ICustomerService { private readonly ICustomerRepository _customerRepository; private readonly IOrderRepository _orderRepository; public CustomerService( ICustomerRepository customerRepository, IOrderRepository orderRepository) { _customerRepository = customerRepository; _orderRepository = orderRepository; } public int CreateOrder(Order o, Customer c) { // Do something with _customerRepository and _orderRepository } }
在XML文件中,您可以选择要在事务中执行的方法:
在您的代码中,您将获得CustomerService类的实例,如下所示:
ICustomerService customerService = (ICustomerService)ContextRegistry .GetContent() .GetObject("customerService");
Spring.NET将返回CustomerService类的代理,该类将在您调用CreateOrder方法时应用事务.这样,服务类中就没有特定于事务的代码.AOP照顾它.有关更多详细信息,您可以查看Spring.NET的文档.