Транзакции NHibernate в рамках сеансов UnitOfWork

В проекте, над которым я работаю, UnitOfWork определен для всего сеанса (что, как представляется, является стандартной практикой для сайтов MVC + NHibernate)

Что я должен сделать, так это уметь циклически перебирать коллекцию элементов и вставлять их один за другим в свою собственную "локальную" транзакцию.

что-то вроде этого:

foreach(var item in CollectionOfItems)
 {
      using (ITransaction transaction = UnitOfWork.CurrentSession.BeginTransaction())
      {
         //do work on item. rollback on failure, 
         //but it should not affect the other items
      }
 }

Но это не сработает, потому что строка BeginTransaction использует тот же "внешний" сеанс. Как я могу получить автономный "локальный" сеанс для выполнения транзакции с небольшим блоком кода? Я думаю, что сессия вводится в единицу работы в следующем коде. Я не знаю точно, как, хотя:

Класс UnitOfWOrk имеет следующий конструктор

    private readonly ISessionFactory _sessionFactory;
    private readonly ITransaction _transaction;

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

Он зарегистрирован через:

For<IUnitOfWork>().LifecycleIs(new HybridLifecycle())
            .Use<UnitOfWork>();

Поэтому всякий раз, когда контроллер возвращает ответ, сеанс сбрасывается. Это где я запутался. Я не всегда хочу, чтобы все было всем или ничем.

РЕДАКТИРОВАТЬ:

Вот весь код для процесса регистрации NHibernate

    public NHibernateRegistry()
    {
        FluentConfiguration fluentConfig = Fluently.Configure()
            .Database(
                MsSqlConfiguration.MsSql2008.ShowSql().ConnectionString(x => x.FromConnectionStringWithKey("conn")))
            .ProxyFactoryFactory(typeof (ProxyFactoryFactory).AssemblyQualifiedName)
            .Mappings(m => m.FluentMappings.AddFromAssemblyOf<CustomerMap>());


        Configuration configuration = fluentConfig.BuildConfiguration();

        ConfigureNhibernateValidator(configuration);

        ISessionFactory sessionFactory = fluentConfig.BuildSessionFactory();

        For<Configuration>().LifecycleIs(new HybridLifecycle()).Singleton().Use(configuration);

        For<ISessionFactory>().LifecycleIs(new HybridLifecycle()).Singleton().Use(sessionFactory);

        For<ISession>().LifecycleIs(new HybridLifecycle())
            .Use(x => x.GetInstance<ISessionFactory>().OpenSession());

        For<IUnitOfWork>().LifecycleIs(new HybridLifecycle())
            .Use<UnitOfWork>();

        For<ITssPrincipal>().HybridHttpOrThreadLocalScoped().Use(container => BuildUserInstanceFromThreadCurrentPrincipal());

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

РЕДАКТИРОВАТЬ: пример проблемы DI В приведенном ниже примере вы видите, что RepoA является DI'd с RepoB, и оба получают UnitOfWork, предоставляемый StructureMap.

public RepoA(IUnitOfWork unitOfWork, ITssPrincipal principal,
     IRepoB repoB)
{
}

public RepoB(IUnitOfWork unitOfWork, ITssPrincipal principal)
{
}

Даже если я создам новый сеанс в функции в RepoA, repoB все равно будет использовать исходный сеанс UnitOfWork

1 ответ

Похоже, ваш веб-сайт MVC использует StructureMap в качестве контейнера для внедрения зависимостей, что позволяет очень легко делать то, что вы хотите.

У вас есть несколько вариантов, но проще всего будет просто запросить новый экземпляр ISession из StructureMap. Это вернет вам новую и другую ISession, чем та, которую использует UnitOfWork.

Вот пример:

var session = StructureMap.ObjectFactory.GetInstance<ISession>();

using ( var tx = session.BeginTransaction() )
{
    try
    {
        // Do your work here

        tx.Commit();
    }
    catch ( Exception )
    {
        tx.Rollback();

        throw;
    }
}

Поскольку вы используете DI-контейнер, вы также можете использовать внедрение зависимостей StructureMap и внедрить новую ISession в конструктор вашего контроллера / класса / репозитория и т. Д., Чтобы вам не пришлось вызывать ObjectMactory.GetInstance StructureMap<>() метод.

Другие вопросы по тегам