【发布时间】:2013-09-04 09:47:32
【问题描述】:
Martin Fowler 定义的存储库应该像内存中的域对象集合一样工作。这使得应用程序(理论上)可以忽略持久性机制。
所以在正常情况下你会有这样的东西:
public void MyBusinessLogicMethod () {
...
IRepository<Customer> repository = myIocContainer.Resolve<IRepository<Customer>>();
repository.Add(customer);
}
但是,如果您希望执行一系列插入/更新并希望在其中任何一个失败时回滚的机制,您将需要某种 UnitOfWork 实现:
public void MyBusinessLogicMethod () {
...
using (IUnitOfWork uow = new UnitOfWork()){
IRepository<Customer> customerRepo = myIocContainer.Resolve<IRepository<Customer>>(uow);
customerRepo.Add(customer);
IRepository<Order> orderRepo = myIocContainer.Resolve<IRepository<Order>>(uow);
orderRepo.Add(order);
IRepository<Invoice> invoiceRepo = myIocContainer.Resolve<IRepository<Invoice>>(uow);
invoiceRepo.Update(invoice);
uow.Save();
}
}
但是,如果您有一些奇怪的要求,即您的客户存储库针对 SqlServer 数据库、您的订单存储库针对 MySql 数据库以及您的发票存储库针对 PostgreSQL 数据库,您将如何处理每个数据库会话的事务?
现在这肯定是一个人为的例子,但我遇到的每个 Repository 实现似乎在某种程度上都知道它实际上是一个特定的数据库和正在使用的 ORM。
想象另一种情况,您有 2 个存储库,其中一个用于访问数据库,另一个用于调用 Web 服务。 Repositories 的全部意义在于,应用程序不应该关心您将使用什么数据源,但是如果不跳过一些巨大的障碍,我不知道如果应用程序不知道在某个级别上如何解释这些场景“仅供参考,这是转到数据源 x,所以我们最好区别对待”。
是否有解决此问题的模式或实现?在我看来,如果您在整个应用程序中使用 Database x 和 ORM y,那么 Repositories 工作得非常好,但如果由于技术债务而导致课程偏离,那么 Repositories 的好处就会大大降低。
【问题讨论】:
-
我从来没有理由玩它,但这应该是DTC 解决的问题。部分解决方案是使用
TransactionScope而不是ISession.BeginTransaction(),但据我所知,这差不多。 -
是的,TransactionScope 是值得关注的。这是一个连接和 DbConnection 实现的东西,所有提供者都必须支持两阶段提交。与休眠无关。
-
有趣。是否有一种既定的方式来编写您自己的代码,以便它由 TransactionScope 管理?假设我模拟了我的存储库以针对内存中的集合运行,我可以让它们参与 TransactionScope 吗?
-
您需要自己为此编写事务支持。使用内存数据库进行测试,那么您的测试将真正测试查询执行,并且数据库应该实现 DTC。
标签: c# nhibernate repository