简体   繁体   English

使用IRepository的C#共享事务和NHibernate

[英]C# Shared Transactions and NHibernate using IRepository

I'm looking into implementing the IRepository pattern using NHibernate and I have question that I've not been able to answer searching the net. 我正在考虑使用NHibernate实现IRepository模式,但我有一个问题,就是我无法回答搜索网络问题。

Assume I have 3 Repositories, PersonRepository, PersonAddressRepository and PersonAccountRepository. 假设我有3个存储库,PersonRepository,PersonAddressRepository和PersonAccountRepository。 Now assume that business logic dictates that there be an "Deactivate Person" process that calls PersonRepository.Deactivate(), PersonAddressRepository.Deactivate() and PersonAccountRepository.Deactivate(). 现在,假定业务逻辑规定存在一个调用PersonRepository.Deactivate(),PersonAddressRepository.Deactivate()和PersonAccountRepository.Deactivate()的“停用Person”过程。

I want to be able to do something along the lines of.. 我希望能够做一些类似的事情。

using (ITransaction transaction = session.BeginTransaction()) { 
    session.Update(Person);
    session.Update(PersonAddress);
    session.Update(PersonAccount);
}

So that if any of those updates fail that the entire process rolls back within the database. 因此,如果这些更新中的任何一个失败,整个过程将在数据库中回滚。 Now at the moment my understanding of NHibernate is you can only create a Session per object so.. 现在,我对NHibernate的了解是,您只能为每个对象创建一个Session。

var cfg = new Configuration();
cfg.Configure();
cfg.AddAssembly(typeof(Person).Assembly);
ISessionFactory sessionFactory = cfg.BuildSessionFactory();
using (ISession session = sessionFactory.OpenSession()) {
    using (ITransaction transaction = session.BeginTransaction()) {
    session.Save(Person);
}

Is this correct or am I mistaken? 这是正确的还是我弄错了? What are the best practices for Transactions regarding multi table updates and Transactions with regards to NHibernate. 关于多表更新和关于NHibernate的事务的最佳实践是什么?

Thanks in advance. 提前致谢。

You should not create transactions in the repositories or somewhere else "bellow". 您不应在存储库或其他“波纹管”中创建事务。 Transactions are defined by the application logic. 事务由应用程序逻辑定义。 This is one of the most common mistakes I see in transaction handling. 这是我在事务处理中看到的最常见的错误之一。

I wrote a transaction service which manages the transactions: 我写了一个交易服务来管理交易:

using (TransactionService.CreateTransactionScope())
{
  repositoryA.DoX();
  repositoryB.DoY();
  TransactionService.Commit();
}

The repository is getting the session with an open transaction from the service: 存储库正在通过服务从开放事务中获取会话:

TransactionService.Session.CreateQuery("...");

Depending on your environment, you need to make it a bit more complicated. 根据您的环境,您需要使其更加复杂。 For instance, the session may not be visible to the business logic and should to be put onto another interface etc. 例如,会话可能对业务逻辑不可见,应将其放置到另一个接口等上。

I thought NHibernate understands the System.Transactions.TransactionScope class. 我以为NHibernate可以理解System.Transactions.TransactionScope类。 Why wouldn't you use that? 你为什么不使用它?

One thing you can do -this is how I do it right now- is pass the ISession instance that should be used to your repository instances. 您可以做的一件事-这就是我现在的做法-将应该用于存储库实例的ISession实例传递给它。

What I will do, in the future, is this: 将来,我将要做的是:

  • I have a UnitOfWork class, which is quite generic and is a wrapper around NHibernate's ISession object. 我有一个UnitOfWork类,该类非常通用,是NHibernate的ISession对象的包装。 This UnitOfWork class contains no 'application' or domain specific methods 此UnitOfWork类不包含“应用程序”或特定于域的方法

  • In a project which uses NHibernate (and my UnitOfWork wrapper), I'll create a set of extension methods on the UnitOfWork class, that look like this: 在使用NHibernate(和我的UnitOfWork包装器)的项目中,我将在UnitOfWork类上创建一组扩展方法,如下所示:

     public static class UnitOfWorkExtension` { public static IPersonRepository GetPersonRepository( this UnitOfWork uow) { return new PersonRepository(uow); } public static IAccountRepository GetAccountRepository( this UnitofWork uow ) { return new AccountRepository(uow); } } 

Then, this would allow me to do this, for instance: 然后,这将允许我执行此操作,例如:

using( var uow = unitOfWorkFactory.CreateUnitOfWork() )
{
     var person = uow.GetPersonRepository().GetPerson (1);
     var accounts = uow.GetAccountRepository().GetAccountsForPerson(person);
}

But, looking at your example, I'm wondering whether you should have a repository for 'PersonAddress' and 'PersonAccount'. 但是,看看您的示例,我想知道您是否应该为“ PersonAddress”和“ PersonAccount”提供存储库。 In my humble opinion, Person is an 'aggregate root' which consists of a PersonAddress and a PersonAccount in your example, and there should be a PersonRepository which handles the Person aggregate root (including the PersonAddress and PersonAccount objects - which are, in fact not entities but value objects (as I see it)). 以我的拙见,在您的示例中, Person是一个“聚合根”,它由一个PersonAddress和一个PersonAccount组成,并且应该有一个PersonRepository处理该Person的聚合根(包括PersonAddress和PersonAccount对象-实际上,它们不是实体但重视对象(如我所见)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM