Предоставление Ninject управления моим состоянием транзакций, практика

Я разрешаю Ninject управлять состоянием ISession и ITransaction в Fluent nHibnerate со следующим методом регистрации - мне интересно, достаточно ли контролировать транзакции или нужно ли это помещать в другое место.

Мысль о том, что каждый ISession создается по запросу и что Ninject обрабатывает фиксацию всего, что было сделано во время этого запроса.

public class SessionModule : Ninject.Modules.NinjectModule
{
    private static ISessionFactory sessionFactory;

    public override void Load()
    {
        Bind<ISessionFactory>()
            .ToMethod(c => CreateSessionFactory())
            .InSingletonScope();

        Bind<ISession>()
            .ToMethod(c => OpenSession())
            .InRequestScope()
            .OnActivation(session =>
            {
                session.BeginTransaction();
                session.FlushMode = FlushMode.Commit;
            })
            .OnDeactivation(session =>
            {
                if (session.Transaction.IsActive)
                {
                    try
                    {
                        session.Flush();
                        session.Transaction.Commit();
                    }
                    catch
                    {
                        session.Transaction.Rollback();
                    }
                }
            });
    }

    /// <summary>
    /// Create a new <see cref="NHibernate.ISessionFactory"/> to connect to a database.
    /// </summary>
    /// <returns>
    /// A constructed and mapped <see cref="NHibernate.ISessionFactory"/>.
    /// </returns>
    private static ISessionFactory CreateSessionFactory()
    {
        if (sessionFactory == null)
            sessionFactory = Persistence.SessionFactory.Map
                (System.Web.Configuration
                    .WebConfigurationManager
                    .ConnectionStrings["Local"]
                    .ConnectionString
                );
        return sessionFactory;
    }

    /// <summary>
    /// Open a new <see cref="NHibernate.ISession"/> from a <see cref="NHibernate.ISessionFactory"/>.
    /// </summary>
    /// <returns>
    /// A new <see cref="NHibernate.ISession"/>.
    /// </returns>
    private static ISession OpenSession()
    {
        // check to see if we even have a session factory to get a session from
        if (sessionFactory == null)
            CreateSessionFactory();

        // open a new session from the factory if there is no current one
        return sessionFactory.OpenSession();
    }
}

Я просмотрел среду выполнения, используя System.Diagnostics.Debug.WriteLine, чтобы писать, когда что-то происходит, и она делает, как будто это делает то, что я хотел делать. То, о чем я прошу вас, сообщество, является ли это практикой хорошей или нет. Вот мое понимание.

Бесчисленные часы чтения на http://ayende.com/blog/default.aspx привели меня к переоценке большого количества способов управления сеансами.

Многое вникание в документацию nHibernate говорит мне, что мне нужно использовать ITransaction каждый раз, когда что-либо происходит с моей базой данных.

Размещение управления в атрибуте считается недостатком, поскольку оно не соответствует указанному выше утверждению.

Выполнение ITransaction для каждой операции не является правильным процессом, поскольку для управления (A) мои контроллеры требуется доступ к ISession или (B) My IRepository<T>, чтобы иметь логику ITransaction о чем я говорил в предыдущих вопросах, не было хорошей практикой.

Размещение моего ITransaction Менеджмента в HttpModule добавляет ненужные служебные данные, поскольку это дает мне знание HttpContext ISession, и это означает, что я должен сделать какую-то инъекцию в HttpRequest (который я может использовать [Inject], но это не кажется мудрым)

Это привело меня к такому выводу.

  • Транзакции должны начинаться с запроса ISession.
  • Все, что происходит в одиночном запросе, инкапсулируется одним ISession
  • Когда выполняется ITransaction, его необходимо выполнить так, чтобы 2-й уровень кэша мог получить свои результаты.

Может ли кто-нибудь пролить свет на это? Неужели я, наконец, на правильном пути? Или я все еще пропустил это?

Ответ 1

Я не эксперт (и у меня нет опыта работы с ninject), но я согласен с вашими 3 выводами и тем, что я делаю в своих проектах.
Еще одна вещь, которую я могу добавить, это то, что, на мой взгляд, транзакции должны контролироваться EXPLICITLY и за операцию, а не глобально (начало и начало запроса и фиксация в конце), как ваш код. Это связано с тем, что я считаю, что вы хотите контролировать свое поведение транзакции или нет (или, возможно, даже не запускать, если нет доступа к БД) для каждой операции отдельно.
Я использую слой управления (или рабочий процесс, если вы предпочитаете), который отвечает только за это. например:

public class SomeManager : ManagersBase
{
    public void DoSomething(DomainObject obj)
    {
        if (obj.Operation())
        {
            using (ITransaction tx = Session.BeginTransaction())
            {
                try
                {
                    Session.Update(obj);
                    tx.Commit();
                }
                catch (MeaningfulException ex)
                {
                    //handle
                    tx.Rollback();
                }
            }
        }
    }
}

надеюсь, что это поможет