NHibernate, transakcje i TransactionScope

Usiłuję znaleźć najlepsze rozwiązanie do obsługi transakcji w aplikacji internetowej, która używa NHibernate.

Używamy IHttpModule, aw HttpApplication.BeginRequest otwieramy nową sesję i łączymy ją z HttpContext za pomocą ManagedWebSessionContext.Bind (kontekst, sesja); Zamykamy i rozłączamy sesję na HttpApplication.EndRequest.

W naszej klasie bazowej Repozytorium zawsze zawijaliśmy transakcję wokół naszej SaveOrUpdate, Delete, Get metod like, zgodnie znajlepsze praktyki:

        public virtual void Save(T entity)
        {
          var session = DependencyManager.Resolve<ISession>();
          using (var transaction = session.BeginTransaction())
          {
            session.SaveOrUpdate(entity);
            transaction.Commit();
          }
        }

Ale to nie działa, jeśli musisz umieścić transakcję gdzieś np. usługa aplikacji zawierająca kilka wywołań repozytorium do zapisywania, usuwania itp.

Więc próbowaliśmy użyć TransactionScope (nie chciałem pisać własnego menedżera transakcji). Aby przetestować, że to zadziałało, używam zewnętrznego TransactionScope, który nie wywołuje .Complete (), aby wymusić wycofanie:

Zapisz repozytorium ():

    public virtual void Save(T entity)
    {
        using (TransactionScope scope = new TransactionScope())
        {
            var session = DependencyManager.Resolve<ISession>();
            session.SaveOrUpdate(entity);
            scope.Complete();
        }   
    }  

Blok korzystający 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 to by! Dzieje się tak, ponieważ w bazie danych nie ma w ogóle ROLLBACK, ale gdy testRepository.GetById (testEntity.Id); instrukcja jest wykonywana, zamiast tego uruchamiana jest AKTUALIZACJA z SET Text = "TestCahgned" (powinna być uruchomiona między BEGIN TRAN i 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 wycofywanie jest dokonywane w ramach NHibernate, należy również zamknąć i odłączyć bieżącą sesję.

Moje pytanie brzmi: czy ktoś zna dobry sposób, aby to zrobić za pomocą TransactionScope i ManagedWebSessionContext?

questionAnswers(4)

yourAnswerToTheQuestion