Фокусник ловкость рук ! Тем, что можно думать, что Вы видите, можно тайно управлять или заменить.
Эта реализация не поддерживает вложение, если вы хотите использовать вложение, используйте реализацию UnitOfWork Айенде . Другая проблема с реализацией, которую вы используете (по крайней мере, для веб-приложений), заключается в том, что она удерживает экземпляр ISession в статической переменной.
Я только что вчера переписал наш UnitOfWork по этим причинам, он изначально был основан на Габриэле.
Мы не используем UnitOfWork.Current.BeginTransaction (), мы используем UnitofWork.TransactionalFlush (), который создает отдельную транзакцию в самом конце, чтобы сбросить все изменения сразу.
using (var uow = UnitOfWork.Start())
{
var entity = repository.Get(1);
entity.Name = "Sneal";
uow.TransactionalFlush();
}
Я уже некоторое время борюсь с этим. Я собираюсь сделать еще один взлом.
Я хочу реализовать транзакции в отдельных сервисных контейнерах - потому что это делает их самодостаточными, - но затем иметь возможность вложить кучу этих сервисных методов в более крупную транзакцию и при необходимости откатить всю партию.
Поскольку я использую Rhino Commons , я собираюсь попробовать провести рефакторинг с использованием метода With.Transaction
. По сути, это позволяет нам писать код, как если бы транзакции были вложенными, хотя на самом деле существует только одна.
Например:
private Project CreateProject(string name)
{
var project = new Project(name);
With.Transaction(delegate
{
UnitOfWork.CurrentSession.Save(project);
});
return project;
}
private Sample CreateSample(Project project, string code)
{
var sample = new Sample(project, code);
With.Transaction(delegate
{
UnitOfWork.CurrentSession.Save(sample);
});
return sample;
}
private void Test_NoNestedTransaction()
{
var project = CreateProject("Project 1");
}
private void TestNestedTransaction()
{
using (var tx = UnitOfWork.Current.BeginTransaction())
{
try
{
var project = CreateProject("Project 6");
var sample = CreateSample(project, "SAMPLE006", true);
}
catch
{
tx.Rollback();
throw;
}
tx.Commit();
}
}
В Test_NoNestedTransaction ()
мы создаем проект самостоятельно, без контекста более крупной транзакции. В этом случае в CreateSample
будет создана и зафиксирована новая транзакция или откат в случае возникновения исключения.
В Test_NestedTransaction ()
мы создаем и образец, и проект. Если что-то пойдет не так, мы хотим, чтобы оба были откатаны. На самом деле код в CreateSample
и CreateProject
будет работать так же, как если бы транзакций не было вообще; Это полностью внешняя транзакция, которая решает, откатить или зафиксировать, и делает это в зависимости от того, было ли выброшено исключение. На самом деле, поэтому я использую транзакцию, созданную вручную для внешней транзакции; так что у меня есть контроль над фиксацией или откатом, а не просто по умолчанию на on-exception-rollback-else-commit .
Вы могли бы добиться того же и без Rhino.Commons, добавив в свой код множество подобных вещей:
if (!UnitOfWork.Current.IsInActiveTransaction)
{
tx = UnitOfWork.Current.BeginTransaction();
}
_auditRepository.SaveNew(auditEvent);
if (tx != null)
{
tx.Commit();
}
... и так далее. Но With.Transaction
, несмотря на всю громоздкость необходимости создавать анонимные делегаты, делает это довольно удобно.
Преимущество этого подхода перед использованием TransactionScope
(помимо зависимости от MSDTC) состоит в том, что при окончательной фиксации внешней транзакции должен быть только один сброс в базу данных, независимо от того, как многие методы были вызваны промежуточными. Другими словами, нам не нужно записывать незафиксированные данные в базу данных по ходу работы, мы всегда просто записываем их в локальный кеш NHibernate.
Короче говоря, это решение не предлагает окончательного контроля над вашими транзакциями, потому что оно никогда не использует более одной транзакции. Думаю, я могу согласиться с этим, поскольку вложенные транзакции никоим образом не поддерживаются повсеместно в каждой СУБД. Но теперь, возможно, я смогу хотя бы написать код, не беспокоясь о том, находимся мы уже в транзакции или нет.
Сеансы NHibernate не поддерживают вложенные транзакции.
Следующий тест всегда выполняется в версии 2.1.2:
var session = sessionFactory.Open();
var tx1 = session.BeginTransaction();
var tx2 = session.BeginTransaction();
Assert.AreEqual(tx1, tx2);
Вам необходимо заключить его в TransactionScope
для поддержки вложенных транзакций.
MSDTC должен быть включен, иначе вы получите сообщение об ошибке:
{"Сетевой доступ для диспетчера распределенных транзакций (MSDTC) отключен.Включите DTC для доступа к сети в конфигурации безопасности для MSDTC с помощью инструмента администрирования служб компонентов. "}