J'essaie de trouver la meilleure solution pour gérer les transactions dans une application web qui utilise NHibernate.NHibernate, transactions et TransactionScope
Nous utilisons un IHttpModule et à HttpApplication.BeginRequest nous ouvrons une nouvelle session et nous la lions au HttpContext avec ManagedWebSessionContext.Bind (context, session); Nous fermons et dissocions la session sur HttpApplication.EndRequest.
Dans notre classe de base du référentiel, nous enveloppa toujours une transaction autour de notre saveOrUpdate, Supprimer, Obtenez des méthodes telles que, selon best practice:
public virtual void Save(T entity)
{
var session = DependencyManager.Resolve<ISession>();
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(entity);
transaction.Commit();
}
}
Mais cela ne fonctionne pas, si vous avez besoin de mettre un transaction quelque part dans par exemple un service d'application pour inclure plusieurs appels de référentiel à enregistrer, supprimer, etc.
Donc, ce que nous avons essayé est d'utiliser TransactionScope (je ne voulais pas écrire mon propre gestionnaire de transaction). Pour vérifier que cela a fonctionné, j'utilise un TransactionScope externe qui ne remet pas .Complete() pour forcer un rollback:
Repository Save():
public virtual void Save(T entity)
{
using (TransactionScope scope = new TransactionScope())
{
var session = DependencyManager.Resolve<ISession>();
session.SaveOrUpdate(entity);
scope.Complete();
}
}
Le bloc qui utilise le référentiel :
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"));
Cela ne fonctionne pas. Mais pour moi, si NHibernate prend en charge TransactionScope, il le ferait! Qu'est-ce qui se passe est qu'il n'y a pas de ROLLBACK du tout dans la base de données, mais quand le testRepository.GetById (testEntity.Id); instruction est exécutée une UPDATE avec SET Text = "TestCahgned" est déclenché à la place (il aurait dû être déclenché entre BEGIN TRAN et ROLLBACK TRAN). NHibernate lit la valeur du cache de niveau 1 et envoie une UPDATE à la base de données. Comportement non attendu !? D'après ce que je comprends à chaque fois qu'une restauration est effectuée dans le cadre de NHibernate, vous devez également fermer et dissocier la session en cours.
Ma question est la suivante: Quelqu'un connaît-il un bon moyen de le faire en utilisant TransactionScope et ManagedWebSessionContext?
Si vous utilisez TransactionScope, vous devez utiliser NHibernate 2.1. C'est seulement avec 2.1 que NH a vraiment eu une bonne intégration avec TransactionScope. –