У меня есть Веб-приложение, которое соединяется с 2 DBS (одно ядро, другой регистрирующийся DB).
Я должен теперь создать службу Windows, которая будет использовать ту же бизнес-логику / Доступ к данным DLLs. Однако, когда я пытаюсь сослаться на 2 фабрики сессии в Сервисном Приложении и назвать фабрику. 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();
Кто-либо может предложить лучший способ обработать это?
Заранее спасибо!
Ограбить
Первое, что я могу предложить, - сделать оба ваших экземпляра ISessionFactory
статическими. Это должны быть синглтоны, поскольку их создание очень дорогое.
РЕДАКТИРОВАТЬ №1
Вы бы порекомендовали мне создавать сеансы, когда они мне нужны, или оставлять их открытыми?
ISession
API обрабатывает свое соединение внутренне. Через некоторое время, если не требуется взаимодействия с базовой базой данных, соединение закрывается, хотя ваш ISession
сохраняет свой экземпляр соединения. Когда ему нужно выполнить некоторые другие транзакции с базой данных, он повторно открывает ранее использованное соединение.
Чтобы ответить на ваш вопрос, предпочтительным подходом является использование экземпляра ISession
API для каждой страницы (Web) или формы (Desktop). Например, предположим, что у вас есть бухгалтерское программное обеспечение, и у пользователя есть некоторые обязанности по управлению клиентами. Затем, когда ваш CustomerMgmtForm
загружается, вы должны предоставить экземпляр ISession
, чтобы он мог загружать ваших клиентов, отслеживать ваши изменения, удаления и новых клиентов, созданных (после присоединения к ISession
, так что когда вы вызываете метод SaveOrUpdate ()
, ISession
знает, что он должен делать с отслеживаемыми изменениями и временными объектами.
Вам интересно, почему один экземпляр на страницу или на форму?
Поскольку ISession
API отслеживает все изменения, происходящие с объектом, представьте, как только вы загрузите своих клиентов, поставщиков и некоторые другие объекты, о которых вы должны позаботиться в своем приложении. Каждое из изменений производится в отношении клиентов, они не имеют права на поставщиков. Но эти клиенты по-прежнему будут там, потому что это экземпляр ISession
, который вы использовали для своих клиентов! Затем требования вашего приложения к памяти растут с увеличением количества загружаемых объектов. Кроме того, известная проблема заключается в том, что когда ISession
становится слишком большим в памяти, это может вызвать некоторые утечки памяти, а затем NHibernate считает сеанс более недействительным, удаляя все ваши несохраненные изменения и все остальное, поскольку сеанс, который отслеживал ваши объекты, теперь недействителен.
В дополнение к этому, когда вы открываете, скажем, CustomerMgmtForm , вам нужно будет управлять сущностями Customer . Скорее всего, вам не придется отслеживать своих клиентов после того, как вы закроете форму или даже откроете SuppliersMgmtForm , в которой вы будете управлять своими поставщиками. Таким образом у вас будет два экземпляра ISession
API: первый - customerMgmtSession
, другой - suppliersMgmtSession
. Таким образом, они никогда не должны становиться слишком большими, чтобы вызвать утечку памяти, поскольку у них обоих есть свои собственные сущности, которые нужно обрабатывать или о которых нужно заботиться. Оба полностью независимы друг от друга.
Следуя этому подходу, вы должны закрыть и удалить экземпляр ISession
API в событии FormClosing для Windows Forms или любого другого эквивалента в Интернете. Итак, теперь в службе Windows вам нужно решить, какая ситуация является идеальной, и решить, где она будет наиболее подходящей для ваших нужд, в зависимости от того, что делает ваша служба.
Одно но: если ваша служба не требует отслеживания ваших изменений или чего-либо еще в ваших объектах, возможно, более подходящим для использования будет API IStatelessSession
. Используя его, я определенно предлагаю вам открывать или создавать экземпляр сеанса без сохранения состояния только тогда, когда вам нужно взаимодействовать с базовой базой данных, поскольку нет смысла поддерживать IStatelessSession
, поскольку он не работает » • Предоставлять ресурсы для отслеживания изменений, внесенных в ваши объекты. Это главное и, возможно, единственное, если я правильно помню, разница между API ISession
и IStatelessSession
.
РЕДАКТИРОВАТЬ №2
Выполнение этого, как указано выше в моем РЕДАКТИРОВАТЬ №1 , также может помочь вам решить вашу проблему, поскольку вам никогда не придется вызывать ISessionFactory. GetCurrentSession ()
.
Надеюсь, это поможет! =)