NHibernate, transações e TransactionScope

Eu estou tentando encontrar a melhor solução para lidar com transações em um aplicativo da web que usa o NHibernate.

Usamos um IHttpModule e, em HttpApplication.BeginRequest, abrimos uma nova sessão e a vinculamos ao HttpContext com ManagedWebSessionContext.Bind (context, session); Nós fechamos e desvinculamos a sessão em HttpApplication.EndRequest.

Na nossa classe base Repository, sempre envolvemos uma transação em torno de nossos métodos SaveOrUpdate, Delete, Get, como, de acordo commelhor pratica:

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

Mas então isso não funciona, se você precisar colocar uma transação em algum lugar, por ex. um serviço de aplicativo para incluir várias chamadas de repositório para Salvar, Excluir, etc.

Então o que tentamos é usar o TransactionScope (eu não queria escrever meu próprio gerenciador de transações). Para testar isso funcionou, eu uso um TransactionScope externo que não chama .Complete () para forçar uma reversão:

Repositório Salvar ():

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

O bloco que usa o repositório:

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

Isso não funciona. Mas para mim, se NHibernate suporta TransactionScope seria! O que acontece é que não há nenhum ROLLBACK no banco de dados, mas quando o testRepository.GetById (testEntity.Id); declaração é executada uma atualização com SET Text = "TestCahgned" é disparado em vez disso (ele deve ter sido acionado entre BEGIN TRAN e ROLLBACK TRAN). O NHibernate lê o valor do cache level1 e dispara um UPDATE para o banco de dados. Comportamento não esperado!? Pelo que entendi sempre que uma reversão é feita no escopo do NHibernate, você também precisa fechar e desvincular a sessão atual.

Minha pergunta é: Alguém sabe de uma boa maneira de fazer isso usando TransactionScope e ManagedWebSessionContext?

questionAnswers(4)

yourAnswerToTheQuestion