Управление транзакцией NHibernate с помощью StructureMap? - PullRequest
2 голосов
/ 25 июня 2009

Я использую StructureMap в качестве контейнера IoC, а NHibernate - в качестве ORM. В Интернете я нашел пример, который показывает, как StructureMap создает ISessionFactory и ISession, чтобы Factory была одиночной, а Session основывался на HttpContext. Это прекрасно работает, но потом я начал использовать NH Profiler, который сказал мне, что я всегда должен явно использовать транзакции. Итак, я подумал, почему бы не позволить StructureMap справиться с этим и мне? Используя приведенный ниже код, я понял, что все работает нормально, за исключением того, что я не знаю, как / где зафиксировать / откатить мою транзакцию.

Вот как я инициализирую 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();
        });
    });

Все мои репозитории выглядят следующим образом:

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

И типичный метод внутри хранилища выглядит так:

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

Я пытаюсь сделать так, чтобы все методы, которые я вызываю в одном HttpContext, совместно использовали один и тот же сеанс и транзакцию. Это возможно или это совершенно неправильно, и я лаю не на том дереве?

Заранее спасибо!

* 1016 Дан *

1 Ответ

2 голосов
/ 10 октября 2009

Эта проблема была причиной того, что я создал простой UnitOfWork, который сочетает в себе ISession и ITransaction.

В тестах я бы написал следующий код:

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

когда я действительно хотел:

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

Вот моя единица выполнения работы,

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();
        }
    }
}

Что касается того, когда вызывать Commit () (используя ITransaction или UnitOfWork), я считаю, что это должно быть сделано явно до конца вашего запроса. Если вы не вызываете его, то UnitOfWork должен очистить себя, но не зафиксировать. В качестве альтернативы вы можете использовать HttpModule для фиксации в обработчике EndRequest.

...