2011-02-17 2 views
0

Je cherche à implémenter le modèle IRepository en utilisant NHibernate et j'ai une question à laquelle je n'ai pas été capable de répondre en cherchant sur le net. Supposons que j'ai 3 référentiels, PersonRepository, PersonAddressRepository et PersonAccountRepository. Supposons maintenant que la logique métier impose qu'il y ait un processus "Deactivate Person" qui appelle PersonRepository.Deactivate(), PersonAddressRepository.Deactivate() et PersonAccountRepository.Deactivate().C# Transactions partagées et NHibernate utilisant IRepository

Je veux être en mesure de faire quelque chose le long des lignes de ..

using (ITransaction transaction = session.BeginTransaction()) { 
    session.Update(Person); 
    session.Update(PersonAddress); 
    session.Update(PersonAccount); 
} 

Alors que si l'une de ces mises à jour échouent que l'ensemble du processus annule au sein de la base de données. Maintenant, au moment ma compréhension de NHibernate est que vous ne pouvez créer une session par objet pour ..

var cfg = new Configuration(); 
cfg.Configure(); 
cfg.AddAssembly(typeof(Person).Assembly); 
ISessionFactory sessionFactory = cfg.BuildSessionFactory(); 
using (ISession session = sessionFactory.OpenSession()) { 
    using (ITransaction transaction = session.BeginTransaction()) { 
    session.Save(Person); 
} 

Est-ce exact ou je me trompe? Quelles sont les meilleures pratiques pour les transactions concernant les mises à jour multi-tables et les transactions relatives à NHibernate.

Merci d'avance.

Répondre

5

Vous ne devriez pas créer de transactions dans les dépôts ou ailleurs "ci-dessous". Les transactions sont définies par la logique de l'application. C'est l'une des erreurs les plus courantes que je vois dans la gestion des transactions.

j'ai écrit un service de transaction qui gère les transactions:

using (TransactionService.CreateTransactionScope()) 
{ 
    repositoryA.DoX(); 
    repositoryB.DoY(); 
    TransactionService.Commit(); 
} 

Le dépôt devient la session avec une transaction ouverte du service:

TransactionService.Session.CreateQuery("..."); 

En fonction de votre environnement, vous devez le rendre un peu plus compliqué. Par exemple, la session peut ne pas être visible à la logique métier et doit être placée sur une autre interface, etc.

+0

Salut merci pour votre réponse, ma question de suivi est, est ce service de transaction en effet de gérer un pool de transactions de sorte que si un échoue alors toutes les transactions dans le pool sont annulées? Ou existe-t-il un moyen de partager 1 Transaction entre plusieurs référentiels? – David

+0

Il y a une transaction par thread. Bien sûr, d'autres transactions parallèles se poursuivent sur d'autres threads. –

0

Je pensais que NHibernate comprenait la classe System.Transactions.TransactionScope. Pourquoi ne l'utiliseriez-vous pas?

+0

pouvez-vous fournir des exemples de code ou des sources de référence? – Alex

0

Une chose que vous pouvez faire - c'est ce que je fais maintenant - est de passer l'instance ISession qui devrait être utilisée pour vos instances de dépôt.

Ce que je vais faire, à l'avenir, est la suivante:

  • J'ai une classe UnitOfWork, ce qui est assez générique et est un wrapper autour de l'objet ISession NHibernate.Cette classe UnitOfWork ne contient pas « application » ou le domaine des méthodes spécifiques

  • Dans un projet qui utilise NHibernate (et mon emballage de UnitOfWork), je vais créer un ensemble de méthodes d'extension sur la classe UnitOfWork, qui ressemblent à ceci:

    public static class UnitOfWorkExtension` 
    { 
        public static IPersonRepository GetPersonRepository(this UnitOfWork uow) 
        { 
         return new PersonRepository(uow); 
        } 
    
        public static IAccountRepository GetAccountRepository(this UnitofWork uow) 
        { 
         return new AccountRepository(uow); 
        } 
    } 
    

Ensuite, cela me permettrait de le faire, par exemple:

using(var uow = unitOfWorkFactory.CreateUnitOfWork()) 
{ 
    var person = uow.GetPersonRepository().GetPerson (1); 
    var accounts = uow.GetAccountRepository().GetAccountsForPerson(person); 
} 

Mais, en regardant votre exemple, je me demande wheth Vous devriez avoir un dépôt pour 'PersonAddress' et 'PersonAccount'. À mon humble avis, Person est une «racine agrégée» qui se compose d'un PersonAddress et d'un PersonAccount dans votre exemple, et il devrait y avoir un PersonRepository qui gère la racine d'agrégat Person (y compris les objets PersonAddress et PersonAccount - qui sont, en fait pas des entités mais des objets de valeur (comme je le vois)).

Questions connexes