Próbuję znaleźć najlepsze rozwiązanie do obsługi transakcji w aplikacji sieciowej, która używa NHibernate.NHibernate, transakcje i TransactionScope
Używamy modułu IHttpModule i przy HttpApplication.BeginRequest otwieramy nową sesję i wiążemy ją z HttpContext za pomocą ManagedWebSessionContext.Bind (context, session); Zamykamy i rozpakowujemy sesję w HttpApplication.EndRequest.
W naszym repozytorium klasy podstawowej, zawsze owinięty transakcję wokół naszego SaveOrUpdate, Usuń, Zapisz metod, takich jak, według best practice:
public virtual void Save(T entity)
{
var session = DependencyManager.Resolve<ISession>();
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(entity);
transaction.Commit();
}
}
Ale to nie zadziała, jeśli trzeba umieścić transakcja gdzieś w np Usługa aplikacji do włączenia kilku wywołań repozytoriów do Zapisz, Usuń itp.
Staraliśmy się więc użyć TransactionScope (nie chciałem pisać własnego menedżera transakcji). Aby sprawdzić, czy to działa, używam zewnętrzną TransactionScope że nie wymaga .Complete(), aby wymusić wycofywania:
Repository Zapisz():
public virtual void Save(T entity)
{
using (TransactionScope scope = new TransactionScope())
{
var session = DependencyManager.Resolve<ISession>();
session.SaveOrUpdate(entity);
scope.Complete();
}
}
Blok, który korzysta z repozytorium :
TestEntity testEntity = new TestEntity { Text = "Test1" };
ITestRepository testRepository = DependencyManager.Resolve<ITestRepository>();
testRepository.Save(testEntity);
using (var scope = new TransactionScope())
{
TestEntity entityToChange = testRepository.GetById(testEntity.Id);
entityToChange.Text = "TestChanged";
testRepository.Save(entityToChange);
}
TestEntity entityChanged = testRepository.GetById(testEntity.Id);
Assert.That(entityChanged.Text, Is.EqualTo("Test1"));
To nie działa. Ale dla mnie, jeśli NHibernate obsługuje TransactionScope, będzie! Co się dzieje, że w bazie danych nie ma wcale ROLLBACK, ale kiedy testRepository.GetById (testEntity.Id); Instrukcja wykonywana jest UPDATE z SET Text = "TestCahgned" jest uruchamiany zamiast (Powinien zostać uruchomiony pomiędzy BEGIN TRAN a ROLLBACK TRAN). NHibernate odczytuje wartość z pamięci podręcznej poziomu 1 i uruchamia aktualizację do bazy danych. Nie oczekiwane zachowanie !? Z tego co rozumiem za każdym razem, gdy wykonywane jest wycofywanie w zakresie NHibernate, musisz również zamknąć i usunąć powiązanie z bieżącą sesją.
Moje pytanie brzmi: Czy ktokolwiek wie o dobrym sposobie wykonania tego przy użyciu TransactionScope i ManagedWebSessionContext?
Jeśli korzystasz z TransactionScope, musisz użyć NHibernate 2.1. Dopiero w wersji 2.1 NH uzyskał dobrą integrację z TransactionScope. –