Utilisation correcte de L'Unité de NHibernate de l'organisation du travail et de Ninject

j'ai la mise en œuvre suivante et je voudrais savoir si elle fait une utilisation correcte de NHibernate pour les sessions et les transactions.

public interface IUnitOfWork : IDisposable
{
    ISession CurrentSession { get; }
    void Commit();
    void Rollback();
}

public class UnitOfWork : IUnitOfWork
{
    private readonly ISessionFactory _sessionFactory;
    private readonly ITransaction _transaction;

    public UnitOfWork(ISessionFactory sessionFactory)
    {
        _sessionFactory = sessionFactory;
        CurrentSession = _sessionFactory.OpenSession();
        _transaction = CurrentSession.BeginTransaction();
    }

    public ISession CurrentSession { get; private set; }

    public void Dispose()
    {
        CurrentSession.Close();
        CurrentSession = null;
    }

    public void Commit()
    {
        _transaction.Commit();
    }

    public void Rollback()
    {
        if (_transaction.IsActive) _transaction.Rollback();
    }
}

Ninject de liaison

Bind<IUnitOfWork>().To<UnitOfWork>().InTransientScope();
Bind<ISessionFactory>().ToProvider<NHibernateSessionFactoryProvider>().InSingletonScope();
Bind<IRepository>().To<Repository>().InTransientScope();

Voici un exemple d'utilisation:

public class Repository : IRepository
{
    private readonly ISessionFactory _sessionFactory;

    public Repository(ISessionFactory sessionFactory)
    {
        _sessionFactory = sessionFactory;
    }

    public void Add(IObj obj)
    {
        using (var unitOfWork = new UnitOfWork(_sessionFactory))
        {
            unitOfWork.CurrentSession.Save(obj);
            unitOfWork.Commit();
        }         
    }
}

dans ma précédente implémentation j'injecterais IUnitOfWork dans mon constructeur de dépôt comme so

public Repository(IUnitOfWork unitOfWork)
    {...

mais la méthode Dispose() ne s'exécuterait pas provoquant un appel subséquent pour lancer ceci exception: "Impossible d'accéder à un objet supprimé. Nom de l'objet:'AdoTransaction'."

15
demandé sur Brian T 2010-11-24 23:32:23

3 réponses

première observation: votre dépôt ne doit pas propager l'Unité de travail. Cela va à l'encontre de l'objectif de l'Unité de travail. En enregistrant immédiatement vos modifications dans le dépôt, vous" micro-gérez " la Session NHibernate.

l'Unité de travail doit être référencée plus haut dans la pile, dans la couche application/service. Cela vous permet d'avoir un code d'application qui effectue plusieurs actions, potentiellement sur différents dépôts, et toujours à la fin de la propagation tout à la fois.

la classe UnitOfWork elle-même semble Ok, mais vous devriez vous demander si vous en avez vraiment besoin. À NHibernate, l'ISession est votre unité de travail. Votre classe UnitOfWork ne semble pas ajouter beaucoup de valeur (d'autant plus que vous exposez de toute façon la propriété CurrentSession)

mais vous devez penser à toute une vie. Je pense que vous vous trompez sur ce point. La gestion de la durée de vie de la Session dépend du type d'application que vous développez: application web, vous voulez généralement avoir une unité de travail par demande (vous pourriez vouloir google sur 'nhibernate session par demande'). Dans une application de bureau, c'est légèrement plus compliqué, vous aurez la plupart du temps d'une séance par écran " ou "conversation par transaction".

35
répondu jeroenh 2010-11-24 20:57:53

j'ai un type d'application plutôt CRUD, et j'ai implémenté l'Unité de travail avec le motif du dépôt, mais je ne pouvais pas vraiment m'écarter de la séparation Session/Transaction. Les Sessions et les Transactions nécessitent des durées de vie différentes. Dans le monde desktop, une Session est habituellement "par écran" et une Transaction est "par utilisateur-action".

Plus d'informations dans ce excellent article.

Donc ce que j'ai est:

  • IUnitOfWork - > Session Wraps, implements IDisposable
  • IAtomicUnitOfWork -> Enveloppements transaction, met en œuvre IDisposable
  • IRepository -> fournit L'accès Get, Save, Delete et query

j'ai fait en sorte que vous avez besoin d'un IUnitOfWork construire IAtomicUnitOfWork et vous avez besoin d'un IAtomicUnitOfWork construire IRepository, de façon à assurer une bonne gestion des transactions. C'est tout ce que j'ai gagné en implémentant mes propres interfaces.

comme jeroenh l'a dit, Vous êtes presque aussi bien à utiliser ISession et ITransaction mais à la fin je me suis senti un peu mieux en écrivant tout mon code contre une interface que j'ai définie.

8
répondu Scott Whitlock 2010-11-25 01:54:13

une partie importante de la réponse réside dans la taille de vos transactions. En ce moment (comme jeroenh l'a indiqué) la transaction est une invocation par méthode sur votre dépôt. C'est très petit et probablement pas nécessaire. J'ai créé une page ASP.MVC application et il utilise une taille de transaction qui comprend tout d'une seule requête http. Il peut s'agir de plusieurs lectures/mises à jour de bases de données. J'utilise la même unité de travail et Ninject pour le CIO. Regardez, peut-être que quelque chose vous aidera. vos questions:

http://bobcravens.com/2010/06/the-repository-pattern-with-linq-to-fluent-nhibernate-and-mysql/

http://bobcravens.com/2010/07/using-nhibernate-in-asp-net-mvc/

http://bobcravens.com/2010/09/the-repository-pattern-part-2/

http://bobcravens.com/2010/11/using-ninject-to-manage-critical-resources/

espérons que ceci aider.

Bob

3
répondu rcravens 2017-01-26 15:41:32