Каков наилучший подход к управлению сеансом NHibernate для использования в многопоточном сервисном приложении Windows?

У меня есть приложение службы Windows, которое работает с многопоточностью. Я использую NHibernate на уровне доступа к данным этого приложения.

Что вы предлагаете для управления сеансом в этом приложении. Я читал о UNHADdins, это хорошее решение?


person masoud ramezani    schedule 15.06.2011    source источник


Ответы (2)


Я использую встроенные контекстные сеансы NHibernate. О них можно прочитать здесь:

http://nhibernate.info/doc/nhibernate-reference/architecture.html#architecture-current-session

Вот пример того, как я это использую:

public class SessionFactory
{
    protected static ISessionFactory sessionFactory;
    private static ILog log = LogManager.GetLogger(typeof(SessionFactory));

    //Several functions omitted for brevity

    public static ISession GetCurrentSession()
    {
        if(!CurrentSessionContext.HasBind(GetSessionFactory()))
            CurrentSessionContext.Bind(GetSessionFactory().OpenSession());

        return GetSessionFactory().GetCurrentSession();
    }

    public static void DisposeCurrentSession()
    {
        ISession currentSession = CurrentSessionContext.Unbind(GetSessionFactory());

        currentSession.Close();
        currentSession.Dispose();
    }
}

В дополнение к этому у меня есть следующее в моем файле конфигурации спящего режима:

<property name="current_session_context_class">thread_static</property>
person Cole W    schedule 15.06.2011

Я никогда не смотрел на unhaddins, но вот то, что я использую для вещей wcf, вероятно, должно работать и для многопоточных общих вещей, я думаю.

это контекст сеанса:

namespace Common.Infrastructure.WCF
{
    public class NHibernateWcfSessionContext : ICurrentSessionContext
    {
        private readonly ISessionFactoryImplementor factory;

        public NHibernateWcfSessionContext(ISessionFactoryImplementor factory)
        {
            this.factory = factory;
        }

        /// <summary>
        /// Retrieve the current session for the session factory.
        /// </summary>
        /// <returns></returns>
        public ISession CurrentSession()
        {
            Lazy<ISession> initializer;
            var currentSessionFactoryMap = OperationContext.Current.InstanceContext.Extensions.Find<NHibernateContextManager>().SessionFactoryMaps;
            if (currentSessionFactoryMap == null ||
                !currentSessionFactoryMap.TryGetValue(factory, out initializer))
            {
                return null;
            }
            return initializer.Value;
        }

        /// <summary>
        /// Bind a new sessionInitializer to the context of the sessionFactory.
        /// </summary>
        /// <param name="sessionInitializer"></param>
        /// <param name="sessionFactory"></param>
        public static void Bind(Lazy<ISession> sessionInitializer, ISessionFactory sessionFactory)
        {
            var map = OperationContext.Current.InstanceContext.Extensions.Find<NHibernateContextManager>().SessionFactoryMaps;;
            map[sessionFactory] = sessionInitializer;
        }

        /// <summary>
        /// Unbind the current session of the session factory.
        /// </summary>
        /// <param name="sessionFactory"></param>
        /// <returns></returns>
        public static ISession UnBind(ISessionFactory sessionFactory)
        {
            var map = OperationContext.Current.InstanceContext.Extensions.Find<NHibernateContextManager>().SessionFactoryMaps;
            var sessionInitializer = map[sessionFactory];
            map[sessionFactory] = null;
            if (sessionInitializer == null || !sessionInitializer.IsValueCreated) return null;
            return sessionInitializer.Value;
        }
    }
}

это менеджер контекста:

namespace Common.Infrastructure.WCF
{
    class NHibernateContextManager : IExtension<InstanceContext>
    {
        public IDictionary<ISessionFactory, Lazy<ISession>> SessionFactoryMaps = new Dictionary<ISessionFactory, Lazy<ISession>>();

        public void Attach(InstanceContext owner)
        {
            //We have been attached to the Current operation context from the ServiceInstanceProvider
        }

        public void Detach(InstanceContext owner)
        {
        }
    }
}

Редактировать:

чтобы быть ясным, как говорится в другом ответе, статический контекст потока будет работать из коробки. Основное преимущество того, что у меня есть, это 1) вы получаете контроль и 2) его ленивая реализация, поэтому вам не нужно запускать сеанс для каждого потока, если в этом нет необходимости. меньше подключения к БД всегда лучше, имхо.

person nathan gonzalez    schedule 15.06.2011
comment
Я не уверен, что понимаю ваш второй пункт. Сеансы не являются потокобезопасными, поэтому вам нужно запускать другой сеанс для каждого потока. Также NHibernate использует пул соединений, поэтому открытые соединения с базой данных уже сведены к минимуму. Не чини, если не сломалось, имхо. - person Cole W; 16.06.2011
comment
Также в отношении интеграции WCF: если вы используете контекст сеанса ThreadStatic, он будет работать при разработке, но вы столкнетесь со стеной в производстве, когда различные компоненты (например, авторизация, аутентификация) из конвейера wcf выполняются в разных потоках. - Согласно этому сообщению: stackoverflow.com/a/5393312/878612 - person lko; 23.10.2012