Как и где хранить сеанс nhibernate в winforms для запроса - PullRequest
3 голосов
/ 29 января 2011

Справочная информация

Я прочитал все виды блогов и документации по управлению сессиями nhibernate.Моя проблема, мне это нужно как для winforms и webforms.Да, я использую один и тот же слой данных в приложении winforms (windows .exe) и webforms (asp.net web).Я немного прочитал о шаблоне единицы работы и является хорошим выбором для winforms.Сохранение сеанса nhibernate в HttpRequest.Current.Items кажется хорошим способом использования веб-приложений.Но как насчет комбинированной сделки?У меня есть веб-приложения, приложения для Windows и службы WCF, которые должны использовать один и тот же слой данных nhibernate.Итак, вернемся к моему вопросу ...

Я планирую использовать этот дизайн: NhibernateBestPractices в моем веб-приложении, например, так:

private ISession ThreadSession {
    get {
        if (IsInWebContext()) {
            return (ISession)HttpContext.Current.Items[SESSION_KEY];
        }
        else {
            return (ISession)CallContext.GetData(SESSION_KEY); 
        }
    }
    set {
        if (IsInWebContext()) {
            HttpContext.Current.Items[SESSION_KEY] = value;
        }
        else {
            CallContext.SetData(SESSION_KEY, value); // PROBLEM LINE HERE!!!
        }
    }
}

Проблема

Проблема, с которой я сталкиваюсь при использовании этого кода в моем приложении для Windows, связана со строкой

CallContext.SetData(SESSION_KEY, value);

. Если я правильно понимаю CallContext (), это сохранит сеанс открытым.всю жизнь моего приложения Windows, потому что он хранит сессию nhibernate как часть основного потока приложений.И я слышал много плохих вещей о том, что слишком долго держать сессию nhibernate открытой, и я знаю, что по замыслу это не значит оставаться открытой очень долго.Если все мои предположения верны, то приведенная выше строка кода представляет собой «нет, нет».

Учитывая все это, я хотел бы заменить вышеуказанную строку чем-то, что будет чаще разрушать сеанс nhibernate вприложение для WindowsНечто похожее на время жизни HttpRequest.Я не хочу предоставлять клиенту Windows информацию о сеансе (или транзакции) nhibernate и о том, когда его открывать и закрывать.Я хотел бы, чтобы это запускалось автоматически.

Вопрос

Итак, где я могу сохранить сеанс nhibernate в приложении для Windows, которое позволит мне (т.е.что-то кроме клиента) для автоматического начала и завершения транзакции по запросу к базе данных (то есть всякий раз, когда клиент делает вызов в БД)?

** Обновление **

Вот еще 2 ссылки о том, как реализовать шаблон единицы работы

http://msdn.microsoft.com/en-us/magazine/dd882510.aspx

http://www.codeinsanity.com/2008/09/unit-of-work-pattern.html

Ответы [ 2 ]

1 голос
/ 02 февраля 2011

В итоге я использовал следующий код. Единственным «бременем», которое он наложил на мое приложение, были модульные тесты, и я бы предпочел испортить этот код информацией, специфичной для сеанса, а именно рабочим кодом. Я сохранил тот же код, который упоминался в моем вопросе, а затем добавил этот класс в свой проект модульного теста:

namespace MyUnitTests
{
    /// <summary>
    /// Simulates the IHttpModule class but for windows apps.  
    /// There's no need to call BeginSession() and EndSession() 
    /// if you wrap the object in a "using" statement.
    /// </summary>
    public class NhibernateSessionModule : IDisposable
    {
        public NhibernateSessionModule()
        {
            NHibernateSessionManager.Instance.BeginTransaction();
        }

        public void BeginSession()
        {
            NHibernateSessionManager.Instance.BeginTransaction();
        }

        public void EndSession()
        {
            NHibernateSessionManager.Instance.CommitTransaction();
            NHibernateSessionManager.Instance.CloseSession();
        }

        public void RollBackSession()
        {
            NHibernateSessionManager.Instance.RollbackTransaction();
        }

        #region Implementation of IDisposable

        public void Dispose()
        {
            // if an Exception was NOT thrown then commit the transaction
            if (Marshal.GetExceptionCode() == 0)
            {
                NHibernateSessionManager.Instance.CommitTransaction();
            }
            else
            {
                NHibernateSessionManager.Instance.RollbackTransaction();
            }
            CloseSession();
        }

        #endregion
    }
}

И чтобы использовать вышеупомянутый класс, вы должны сделать что-то вроде этого:

[Test]
public void GetByIdTest()
{
    // begins an nhibernate session and transaction
    using (new NhibernateSessionModule())
    {
        IMyCustomer myCust = MyCustomerDao.GetById(123);
        Assert.IsNotNull(myCust);           
    } // ends the nhibernate transaction AND the session
}

Примечание: Если вы используете этот метод, убедитесь, что вы не включаете свои сеансы в операторы "using" при выполнении запросов из ваших классов Dao, как в в этом посте . Поскольку вы сами управляете сеансами и держите их открытыми дольше, чем один сеанс на запрос, вам нужно избавиться от всех мест, в которых вы закрываете сеанс, и позволить NhibernateSessionModule сделать это за вас (веб-приложения или приложения Windows ).

1 голос
/ 29 января 2011

Каждое из ваших приложений может предоставлять общую реализацию интерфейса, такого как IUnitOfWorkStorage

public interface IUnitOfWorkStorage
{
    void StoreUnitOfWork(IUnitOfWork uow);
}

IUnitOfWork может быть оболочкой для ISession, которая может выглядеть следующим образом

public interface IUnitOfWork
{
   void Begin();
   void End();
}

Begin может открыть сеанс и запустить транзакцию, а End подтвердит транзакцию и закроет сеанс. Таким образом, вы можете иметь 2 реализации IUnitOfWorkStorage, одну для WebApp и одну для приложения Windows. Веб-приложение может использовать HttpContext.Current или что-то в этом роде, а ваше Windows-приложение может предоставить только простое хранилище объектов, которое расположено в конце вашего действия и завершит работу UnitOfWork.

...