Веб-приложение NHibernate Session Management Лето в стиле NHibernate - PullRequest
2 голосов
/ 12 октября 2010

Я пишу веб-приложение с использованием ASP.NET MVC 2 и выбрал NHibernate в качестве своего ORM.Я в основном изучил свои основы, наблюдая серию Summer of NHibernate, и применил для каждого сеанса стратегию сессий авторов (Ep 13).Кажется, все работает хорошо, но меня беспокоит вопрос о том, является ли это функциональным подходом реального мира к управлению сеансом и поточной безопасности.Если нет, то я открыт для других примеров.

Я добавил код для уточнения.Вот мой код, который устанавливает SessionFactory:

public class NHibernateSessionManager
{
    public static readonly ISessionFactory SessionFactory;

    static NHibernateSessionManager()
    {
        try
        {
            Configuration cfg = new Configuration();

            if (SessionFactory != null)
                throw new Exception("trying to init SessionFactory twice!");

            SessionFactory = cfg.Configure().BuildSessionFactory();
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine(ex);
            throw new Exception("NHibernate initialization failed", ex);
        }
    }
    public static ISession OpenSession()
    {
        return SessionFactory.OpenSession();
    }
}

И здесь у меня есть веб-запрос на запуск и остановку транзакции:

public class NHibernateSessionPerRequestModule : IHttpModule
{
    public void Dispose()
    {
    }

    public void Init(HttpApplication context)
    {
        context.BeginRequest +=new EventHandler(Application_BeginRequest);
        context.EndRequest +=new EventHandler(Application_EndRequest);
    }

    private void Application_BeginRequest(object sender, EventArgs e)
    {
        ISession session = NHibernateSessionManager.OpenSession();
        session.BeginTransaction();
        CurrentSessionContext.Bind(session);
    }
    private void Application_EndRequest(object sender, EventArgs e)
    {
        ISession session = CurrentSessionContext.Unbind(NHibernateSessionManager.SessionFactory);
        if(session != null)
            try
            {
                session.Transaction.Commit();
            }
            catch (Exception)
            {
                session.Transaction.Rollback();
            }
            finally
            {
                session.Close();
            }
    }
}

И вот как я мог бы получитьсеанс из фабрики сеансов для одного из моих репозиториев в классе Controller:

CompanyRepository _companyRepository = new CompanyRepository(NHibernateSessionManager.SessionFactory.GetCurrentSession());

Ответы [ 2 ]

1 голос
/ 14 октября 2010

Взяв страницу от jfar, я думаю, что наконец-то научился ловить рыбу (или, может быть, бросил свой шест в правильном направлении) по этому вопросу и нашел несколько хороших статей, которые пролили некоторый свет на подробное описание работы схемы Summer of NHibernate. Поиск в Google, чтобы найти больше деталей о NHibernate и Contextual Sessions, помог мне лучше понять тему. Я все еще новичок в NHibernate (и веб-программировании в целом), поэтому, пожалуйста, потерпите меня, если этот вопрос и ответ кажутся элементарными.

Кажется, схема Summer of NHibernate является поточно-ориентированной. Мое объяснение будет ссылаться на имена из моего примера кода выше. Переменная SessionFactory является статической, поэтому она доступна из каждого потока, однако является потокобезопасным объектом (тогда как, как уже упоминалось, ISession не является потокобезопасным). NHibernateSessionPerRequestModule устанавливает два события, которые срабатывают по веб-запросу (Application_BeginRequest) и по окончании одного (Application_EndRequest). Application_BeginRequest получит объект ISession, из которого вы можете затем связать его с текущим контекстом. Это помогает гарантировать, что объект ISession используется во время веб-запроса и только для этого потока. После начала веб-запроса ISession затем можно извлечь с помощью .GetCurrentSession () для использования с _companyRepository. Application_BeginRequest также начнет транзакцию для вас. Application_EndRequest отвяжет объект ISession, зафиксирует все изменения в конце вашего веб-запроса и закроет ISession.

У Питера Вигла есть статья, в которой показан похожий пример того, как реализовать управление сессиями: http://pwigle.wordpress.com/2008/11/21/nhibernate-session-handling-in-aspnet-the-easy-way

В этой статье Global.asax используется для указания событий для привязки и отмены привязки вместо создания IHttpModule.

У Ayende есть хороший чистый пример, который использует HttpContext для управления вашими ISessions: http://ayende.com/Blog/archive/2009/08/05/do-you-need-a-framework.aspx

Если я далеко от базы и не понимаю что-то, пожалуйста, не стесняйтесь вставлять, но, насколько я могу судить, поскольку разные ISession привязаны к каждому контексту потока, это будет потокобезопасным (если нет необходимо иметь многопоточную сессию IS.)

1 голос
/ 12 октября 2010

Мне было любопытно, поэтому я погуглил.

HttpContext.Items может использоваться несколькими потоками.

Сеансы Nhibernate не являются поточно-безопасными.

И затем естьТам ответ: (возможно, обман) Безопасность потока NHibernate с сеансом

Так что, похоже, этот рецепт для катастрофы можно эффективно управлять.Поскольку вы не опубликовали код, который использует Summer of Nhibernate, трудно сказать, не упадет ли ваша реализация.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...