2 Stimmen

Steuerung von NHibernate ITransaction mit StructureMap?

Ich verwende StructureMap als meinen IoC-Container und NHibernate als meinen ORM. Ich habe online ein Beispiel gefunden, das zeigt, wie StructureMap die ISessionFactory und die ISession erstellt, so dass die Factory ein Singleton ist und die Session auf dem HttpContext basiert. Das funktioniert prima, aber dann habe ich den NH Profiler verwendet, der mir sagte, dass ich immer explizit Transaktionen verwenden sollte. Also dachte ich mir, warum sollte StructureMap das nicht auch für mich erledigen? Mit dem unten stehenden Code habe ich das alles gut hinbekommen, nur weiß ich nicht, wie/wo ich meine Transaktion festschreiben/zurücknehmen soll.

So initialisiere ich StructureMap:

    ObjectFactory.Initialize(x =>
    {
        x.ForRequestedType<ISessionFactory>()
            .CacheBy(InstanceScope.Singleton)
            .TheDefault.Is.ConstructedBy(cfg.BuildSessionFactory);

        x.ForRequestedType<ISession>()
            .CacheBy(InstanceScope.Hybrid)
            .TheDefault.Is.ConstructedBy(context => context.GetInstance<ISessionFactory>().OpenSession());

        x.ForRequestedType<ITransaction>()
            .CacheBy(InstanceScope.Hybrid)
            .TheDefault.Is.ConstructedBy(context => context.GetInstance<ISession>().BeginTransaction());

        x.Scan(y =>
        {
            y.TheCallingAssembly();
            y.WithDefaultConventions();
        });
    });

Alle meine Repositories sehen wie folgt aus:

    public UserRepository(ISession session, ITransaction transaction)
    {
        _session = session;
        _transaction = transaction;
    }

Und eine typische Methode innerhalb eines Repositorys sieht so aus:

    public void Remove(int id)
    {
        Remove(_session.Get<User>(id));
    }

Was ich versuche zu tun ist, haben alle Methoden, die ich in einem HttpContext aufrufen, teilen die gleiche Sitzung und Transaktion. Ist dies möglich oder ist dies völlig falsch und ich bin barking up the wrong tree?

Vielen Dank im Voraus!

-Dan

2voto

wbinford Punkte 375

Aus diesem Grund habe ich eine einfache UnitOfWork erstellt, die ISession und ITransaction kombiniert.

In Tests würde ich den folgenden Code schreiben:

var product = new Product {Name = "Apple", Category = "Fruits"};
using (var session = _sessionFactory.OpenSession())
using (var transaction = _session.BeginTransaction())
{
    session.Save(product);
    transaction.Commit();
}

als ich wirklich wollte:

var product = new Product {Name = "Apple", Category = "Fruits"};
using (var unitOfWork = new UnitOfWork(_sessionFactory))
{
    unitOfWork.CurrentSession.Save(product);
    unitOfWork.Commit();
}

Hier ist meine Umsetzung der Arbeitseinheit,

using NHibernate;

namespace NHibernateBootstrap.Core.Persistence
{
    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();
        }
    }
}

Was den Zeitpunkt des Aufrufs von Commit() angeht (entweder mit ITransaction oder UnitOfWork), so glaube ich, dass dies explizit vor dem Ende Ihrer Anfrage erfolgen sollte. Wenn man es nicht aufruft, sollte UnitOfWork sich selbst aufräumen, aber nicht committen. Alternativ könnten Sie ein HttpModule verwenden, um in einem EndRequest-Handler zu übertragen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X