Несколько SessionFactories в Windows Service с NHibernate - PullRequest
6 голосов
/ 28 мая 2010

У меня есть веб-приложение, которое подключается к 2 БД (одно ядро, другое - БД журналирования).

Теперь я должен создать службу Windows, которая будет использовать те же библиотеки DLL бизнес-логики / доступа к данным. Однако, когда я пытаюсь сослаться на 2 фабрики сеансов в приложении-службе и вызываю метод factory.GetCurrentSession (), я получаю сообщение об ошибке «Сеанс не привязан к текущему контексту».

У кого-нибудь есть предложения о том, как это можно сделать?

public class StaticSessionManager
{
    public static readonly ISessionFactory SessionFactory;
    public static readonly ISessionFactory LoggingSessionFactory;

    static StaticSessionManager()
    {
         string fileName = System.Configuration.ConfigurationSettings.AppSettings["DefaultNHihbernateConfigFile"];
         string executingPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
         fileName = executingPath + "\\" + fileName;
         SessionFactory = cfg.Configure(fileName).BuildSessionFactory();

         cfg = new Configuration();
         fileName = System.Configuration.ConfigurationSettings.AppSettings["LoggingNHihbernateConfigFile"];
         fileName = executingPath + "\\" + fileName;
         LoggingSessionFactory = cfg.Configure(fileName).BuildSessionFactory();
    }
}  

Файл конфигурации имеет настройку:

<property name="current_session_context_class">call</property>

Сервис настраивает фабрики:

private ISession _session = null;
private ISession _loggingSession = null;
private ISessionFactory _sessionFactory = StaticSessionManager.SessionFactory;
private ISessionFactory _loggingSessionFactory = StaticSessionManager.LoggingSessionFactory;

...

_sessionFactory = StaticSessionManager.SessionFactory;
_loggingSessionFactory = StaticSessionManager.LoggingSessionFactory;

_session = _sessionFactory.OpenSession();
NHibernate.Context.CurrentSessionContext.Bind(_session);
_loggingSession = _loggingSessionFactory.OpenSession();
NHibernate.Context.CurrentSessionContext.Bind(_loggingSession);

Итак, наконец, я пытаюсь назвать правильную фабрику:

ISession session = StaticSessionManager.SessionFactory.GetCurrentSession();

Кто-нибудь может предложить лучший способ справиться с этим?
Заранее спасибо!
Роб

1 Ответ

4 голосов
/ 28 мая 2010

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

РЕДАКТИРОВАТЬ # 1

Вы бы порекомендовали мне создавать сессии, когда они мне нужны, или оставить их открытыми?

API ISession внутренне обрабатывает свое соединение. Через некоторое время, если не запрашивается взаимодействие с базовой базой данных, соединение закрывается, хотя ваш ISession сохраняет свой экземпляр соединения. Как только ему нужно выполнить некоторые другие транзакции с базой данных, он снова открывает ранее использованное соединение.

Чтобы ответить на ваш вопрос, предпочтительный подход - это экземпляр ISession API на страницу (в Интернете) или на форму (на рабочем столе). Например, давайте рассмотрим, что у вас есть бухгалтерское программное обеспечение, а пользователь должен управлять клиентами. Затем, когда ваш CustomerMgmtForm загружается, вы должны предоставить экземпляр ISession, чтобы он мог загружать ваших клиентов, отслеживать ваши изменения, удаления и новых созданных клиентов (после присоединения к ISession, чтобы при вызове метод SaveOrUpdate(), ISession знает, что он должен делать с отслеживаемыми изменениями и временными объектами.

Почему вам нужен один экземпляр на страницу или на форму?

Поскольку API ISession отслеживает все изменения, происходящие с объектом, представьте, как только вы загрузили своих клиентов, поставщиков и некоторые другие объекты, о которых вам нужно позаботиться в вашем приложении. Каждое из изменений, выполненных над клиентами, они не имеют права над поставщиками. Но эти клиенты все еще будут там, потому что это экземпляр ISession, который вы использовали для своих клиентов! Затем требования вашего приложения к памяти растут с увеличением количества загруженных объектов. Кроме того, известна проблема, заключающаяся в том, что когда ISession становится слишком большим в памяти, это может вызвать некоторые утечки памяти, которые затем рассматриваются NHibernate как более недопустимый сеанс, отбрасывая все ваши несохраненные изменения и все, как отслеживаемый сеанс ваши объекты теперь недействительны.

В дополнение к этому, когда вы откроете, скажем, CustomerMgmtForm , вам придется управлять Customer сущностями. Скорее всего, вам не придется отслеживать своих клиентов после того, как вы закрыли форму или даже открыли SuppliersMgmtForm , в рамках которого вы будете управлять своими поставщиками. Таким образом, у вас будет два экземпляра API ISession: первый - customerMgmtSession, другой - suppliersMgmtSession. Таким образом, они никогда не должны становиться слишком большими, чтобы вызвать утечку памяти, поскольку у них обоих есть свои собственные сущности, с которыми нужно обращаться или заботиться. Оба абсолютно независимы друг от друга.

Следуя этому подходу, вы должны закрыть и утилизировать экземпляр ISession API для события FormClosing для Windows Forms или любого другого аналога в Web. Так что теперь, в Службе Windows, вам решать, что является идеальной ситуацией, и решать, где она будет наиболее подходящей для ваших нужд, в зависимости от того, что делает ваша служба.

Одна вещь, хотя, если ваша служба не требует отслеживания ваших изменений или чего-либо еще в отношении ваших сущностей, IStatelessSession API, возможно, более уместно использовать. Используя его, я наверняка предлагаю вам открывать или создавать сеанс без сохранения состояния только тогда, когда вам нужно взаимодействовать с базовой базой данных, поскольку нет смысла поддерживать IStatelessSession в живых, поскольку он не предоставляет ресурсы отслеживать любые изменения, внесенные в ваши объекты. Это главное и, если я правильно помню, разница между API ISession и IStatelessSession.

РЕДАКТИРОВАТЬ # 2

Это, как указано выше в моей РЕДАКТИРОВАТЬ # 1 , также может помочь вам решить вашу проблему, так как вам не нужно будет звонить ISessionFactory.GetCurrentSession().

Надеюсь, это поможет! =)

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