Совместно используемые транзакции C # и NHibernate с использованием IRepository - PullRequest
0 голосов
/ 17 февраля 2011

Я смотрю на реализацию шаблона IRepository с помощью NHibernate, и у меня есть вопрос, на который я не смог ответить при поиске в сети.

Предположим, у меня есть 3 репозитория, PersonRepository, PersonAddressRepository и PersonAccountRepository. Теперь предположим, что бизнес-логика диктует наличие процесса «Деактивация Person», который вызывает PersonRepository.Deactivate (), PersonAddressRepository.Deactivate () и PersonAccountRepository.Deactivate ().

Я хочу быть в состоянии сделать что-то вроде ..

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

Чтобы при сбое любого из этих обновлений весь процесс откатывался назад в базе данных. Сейчас я понимаю NHibernate так: вы можете создавать сессию только для одного объекта, поэтому ..

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);
}

Это правильно или я ошибаюсь? Каковы лучшие практики для Транзакций в отношении многостоловых обновлений и Транзакций в отношении NHibernate.

Заранее спасибо.

Ответы [ 3 ]

5 голосов
/ 17 февраля 2011

Не следует создавать транзакции в репозиториях или где-то еще «ниже».Транзакции определяются логикой приложения.Это одна из наиболее распространенных ошибок, с которыми я сталкиваюсь при обработке транзакций.

Я написал сервис транзакций, который управляет транзакциями:

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

Хранилище получает сеанс с открытой транзакциейуслуга:

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

В зависимости от вашей среды, вам нужно сделать это немного сложнее.Например, сеанс может быть невидим для бизнес-логики и должен быть помещен в другой интерфейс и т. Д.

0 голосов
/ 17 февраля 2011

Одна вещь, которую вы можете сделать - это то, как я это делаю прямо сейчас, - это передать экземпляр ISession, который должен использоваться для ваших экземпляров репозитория.

В будущем я сделаю следующее:

  • У меня есть класс UnitOfWork, который является довольно общим и является оберткой вокруг объекта ISession NHibernate.Этот класс UnitOfWork не содержит методов, специфичных для приложения или домена

  • В проекте, который использует 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);
        }
    }
    

Тогда это позволит мне сделать это, например:

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

Но, глядя на вашНапример, мне интересно, нужно ли вам иметь хранилище для «PersonAddress» и «PersonAccount».По моему скромному мнению, Person - это «совокупный корень», который состоит из PersonAddress и PersonAccount в вашем примере, и должен быть PersonRepository, который обрабатывает совокупный корень Person (включая PersonAddress и PersonAccountобъекты - которые на самом деле являются не сущностями, а ценными объектами (как я понимаю)).

0 голосов
/ 17 февраля 2011

Я думал, что NHibernate понимает класс System.Transactions.TransactionScope.Почему бы тебе не использовать это?

...