Позвольте Ninject управлять моим состоянием транзакции - PullRequest
11 голосов
/ 19 марта 2011

Я позволяю 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 Management в HttpModule добавляет ненужные накладные расходы, так как дает HttpContext знание о ISession, и это означает, что я должен сделать какую-то инъекцию в HttpRequest (которую я можно использовать [Inject], но это не кажется разумным)

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

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

Кто-нибудь может пролить свет на это? Я, наконец, на правильном пути? Или я до сих пор полностью упустил суть?

1 Ответ

2 голосов
/ 27 марта 2011

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

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

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

...