NHibernate - хороший полный рабочий класс Helper для управления SessionFactory / Session

Может ли кто-нибудь предоставить / указать соответствующий вспомогательный класс типа OO для управления синглтоном SessionFactory, а затем также для управления сеансами?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
21
0
14 688
5

Ответы 5

Конечно, это то, что я использовал, когда начинал работать с NHibernate:

Сессионная фабрика

public class BaseDataAccess
{

  protected ISession m_session;

  public BaseDataAccess()
  {
    m_session = NHibernateHttpModule.CurrentSession;
  }

  public static ISession OpenSession()
  {
    Configuration config;
    ISessionFactory factory;
    ISession session;
    config = new Configuration();

    if (config == null)
    {
      throw new ArgumentNullException(nameof(config));
    }
    if (factory == null)
    {
      throw new ArgumentNullException(nameof(factory);
    }
    if (session == null)
    {
      throw new ArgumentNullException(nameof(session));
    }

    config.AddAssembly("My.Assembly.Here");
    factory = config.BuildSessionFactory();
    session = factory.OpenSession();
    
    return session;
  }
} 

Сообщите мне, если это поможет.

Проверьте Работы Билли Маккафферти. Его более ранняя версия имела некоторые ограничения, вам нужно было исправить обработку ошибок при закрытии и очистке, и я не уверен, что у меня это правильно, но я опубликую, как я изменил его материал.

Билли также работает над новой структурой, которая использует MVC & nHibernate под названием S#arp Architechure, которую я сейчас использую, и пока все хорошо.

В любом случае, вот моя модифицированная версия его кода. Я не гарантирую точности или полноты, и вы используете это на свой страх и риск. Если вы используете это, убедитесь, что вы закрыли сеанс. Если у вас есть какие-либо вопросы, напишите мне письмо [joshua] [dot] [berke] в [Gmail ... остальное вы знаете].

/// <summary>
/// Handles creation and management of sessions and transactions.  It is a singleton because 
/// building the initial session factory is very expensive. Inspiration for this class came 
/// from Chapter 8 of Hibernate in Action by Bauer and King.  Although it is a sealed singleton
/// you can use TypeMock (http://www.typemock.com) for more flexible testing.
/// </summary>
public sealed class NHibernateSessionManager
{
    private const string DefaultConfigFile = "DefaultAppWeb.Config";
    private static readonly object _syncRoot = new object();
    #region Thread-safe, lazy Singleton

/// <summary>
/// This is a thread-safe, lazy singleton.  See http://www.yoda.arachsys.com/csharp/singleton.html
/// for more details about its implementation.
/// </summary>
public static NHibernateSessionManager Instance
{
    get
    {
        return Nested.NHibernateSessionManager;
    }
}

/// <summary>
/// Private constructor to enforce singleton
/// </summary>
private NHibernateSessionManager() { }

/// <summary>
/// Assists with ensuring thread-safe, lazy singleton
/// </summary>
private class Nested
{
    static Nested() { }
    internal static readonly NHibernateSessionManager NHibernateSessionManager =
        new NHibernateSessionManager();
}

#endregion

/// <summary>
/// This method attempts to find a session factory stored in <see cref = "sessionFactories" />
/// via its name; if it can't be found it creates a new one and adds it the hashtable.
/// </summary>
/// <param name = "sessionFactoryConfigPath">Path location of the factory config</param>
private ISessionFactory GetSessionFactoryFor(string sessionFactoryConfigPath)
{
    Check.Require(!string.IsNullOrEmpty(sessionFactoryConfigPath),
        "sessionFactoryConfigPath may not be null nor empty");

    //  Attempt to retrieve a stored SessionFactory from the hashtable.
    ISessionFactory sessionFactory;// = (ISessionFactory)sessionFactories[sessionFactoryConfigPath];

    //  try and get a session factory if we don't find one create it
    lock (_syncRoot)
    {
        if (!sessionFactories.TryGetValue(sessionFactoryConfigPath, out sessionFactory))
        {
            Configuration cfg = new Configuration();
            if (sessionFactoryConfigPath != DefaultConfigFile)
            {
                Check.Require(File.Exists(sessionFactoryConfigPath),
                    "The config file at '" + sessionFactoryConfigPath + "' could not be found");
                cfg.Configure(sessionFactoryConfigPath);


            }
            else
            {
                cfg.Configure();
            }


            //  Now that we have our Configuration object, create a new SessionFactory
            sessionFactory = cfg.BuildSessionFactory();


            Check.Ensure(sessionFactory != null, "sessionFactory is null and was not built");
            sessionFactories.Add(sessionFactoryConfigPath, sessionFactory);
        }
    }



    return sessionFactory;
}

/// <summary>
/// Allows you to register an interceptor on a new session.  This may not be called if there is already
/// an open session attached to the HttpContext.  If you have an interceptor to be used, modify
/// the HttpModule to call this before calling BeginTransaction().
/// </summary>
public void RegisterInterceptorOn(string sessionFactoryConfigPath, IInterceptor interceptor)
{
    ISession session = (ISession)ContextSessions[sessionFactoryConfigPath];

    if (session != null && session.IsOpen)
    {
        throw new CacheException("You cannot register an interceptor once a session has already been opened");
    }

    GetSessionFrom(sessionFactoryConfigPath, interceptor);
}

public ISession GetSessionFrom(string sessionFactoryConfigPath)
{
    return GetSessionFrom(sessionFactoryConfigPath, null);
}
/// <summary>
/// Gets or creates an ISession using the web / app config file.
/// </summary>
/// <returns></returns>
public ISession GetSessionFrom()
{
    return GetSessionFrom(DefaultConfigFile, null);
}
/// <summary>
/// Gets a session with or without an interceptor.  This method is not called directly; instead,
/// it gets invoked from other public methods.
/// </summary>
private ISession GetSessionFrom(string sessionFactoryConfigPath, IInterceptor interceptor)
{
    var allSessions = ContextSessions;
    ISession session = null;
    if (!allSessions.TryGetValue(sessionFactoryConfigPath, out session))
    {
        if (interceptor != null)
        {
            session = GetSessionFactoryFor(sessionFactoryConfigPath).OpenSession(interceptor);
        }
        else
        {
            session = GetSessionFactoryFor(sessionFactoryConfigPath).OpenSession();
        }

        allSessions[sessionFactoryConfigPath] = session;
    }

    //session.FlushMode = FlushMode.Always;

    Check.Ensure(session != null, "session was null");

    return session;
}

/// <summary>
/// Flushes anything left in the session and closes the connection.
/// </summary>
public void CloseSessionOn(string sessionFactoryConfigPath)
{
    ISession session;
    if (ContextSessions.TryGetValue(sessionFactoryConfigPath, out session))
    {
        if (session.IsOpen)
        {
            session.Flush();
            session.Close();
        }
        ContextSessions.Remove(sessionFactoryConfigPath);

    }

}

public ITransaction BeginTransactionOn(string sessionFactoryConfigPath)
{
    ITransaction transaction;

    if (!ContextTransactions.TryGetValue(sessionFactoryConfigPath, out transaction))
    {
        transaction = GetSessionFrom(sessionFactoryConfigPath).BeginTransaction();
        ContextTransactions.Add(sessionFactoryConfigPath, transaction);
    }

    return transaction;
}

public void CommitTransactionOn(string sessionFactoryConfigPath)
{

    try
    {
        if (HasOpenTransactionOn(sessionFactoryConfigPath))
        {
            ITransaction transaction = (ITransaction)ContextTransactions[sessionFactoryConfigPath];

            transaction.Commit();
            ContextTransactions.Remove(sessionFactoryConfigPath);
        }
    }
    catch (HibernateException he)
    {
        try
        {
            RollbackTransactionOn(sessionFactoryConfigPath);
        }
        finally
        {
            throw he;
        }
    }
}

public bool HasOpenTransactionOn(string sessionFactoryConfigPath)
{
    ITransaction transaction;
    if (ContextTransactions.TryGetValue(sessionFactoryConfigPath, out transaction))
    {

        return !transaction.WasCommitted && !transaction.WasRolledBack;
    }
    return false;
}

public void RollbackTransactionOn(string sessionFactoryConfigPath)
{

    try
    {
        if (HasOpenTransactionOn(sessionFactoryConfigPath))
        {
            ITransaction transaction = (ITransaction)ContextTransactions[sessionFactoryConfigPath];

            transaction.Rollback();
        }

        ContextTransactions.Remove(sessionFactoryConfigPath);
    }
    finally
    {

        ForceCloseSessionOn(sessionFactoryConfigPath);
    }
}

/// <summary>
/// Since multiple databases may be in use, there may be one transaction per database 
/// persisted at any one time.  The easiest way to store them is via a hashtable
/// with the key being tied to session factory.  If within a web context, this uses
/// <see cref = "HttpContext" /> instead of the WinForms specific <see cref = "CallContext" />.  
/// Discussion concerning this found at http://forum.springframework.net/showthread.php?t=572
/// </summary>
private Dictionary<string, ITransaction> ContextTransactions
{
    get
    {
        if (IsInWebContext())
        {
            if (HttpContext.Current.Items[TRANSACTION_KEY] == null)
                HttpContext.Current.Items[TRANSACTION_KEY] = new Dictionary<string, ITransaction>();

            return (Dictionary<string, ITransaction>)HttpContext.Current.Items[TRANSACTION_KEY];
        }
        else
        {
            if (CallContext.GetData(TRANSACTION_KEY) == null)
                CallContext.SetData(TRANSACTION_KEY, new Dictionary<string, ITransaction>());

            return (Dictionary<string, ITransaction>)CallContext.GetData(TRANSACTION_KEY);
        }
    }
}

/// <summary>
/// Since multiple databases may be in use, there may be one session per database 
/// persisted at any one time.  The easiest way to store them is via a hashtable
/// with the key being tied to session factory.  If within a web context, this uses
/// <see cref = "HttpContext" /> instead of the WinForms specific <see cref = "CallContext" />.  
/// Discussion concerning this found at http://forum.springframework.net/showthread.php?t=572
/// </summary>
private Dictionary<string, ISession> ContextSessions
{
    get
    {
        if (IsInWebContext())
        {
            if (HttpContext.Current.Items[SESSION_KEY] == null)
                HttpContext.Current.Items[SESSION_KEY] = new Dictionary<string, ISession>();

            return (Dictionary<string, ISession>)HttpContext.Current.Items[SESSION_KEY];
        }
        else
        {
            if (CallContext.GetData(SESSION_KEY) == null)
                CallContext.SetData(SESSION_KEY, new Dictionary<string, ISession>());

            return (Dictionary<string, ISession>)CallContext.GetData(SESSION_KEY);
        }
    }
}

private bool IsInWebContext()
{
    return HttpContext.Current != null;
}

private Dictionary<string, ISessionFactory> sessionFactories = new Dictionary<string, ISessionFactory>();
private const string TRANSACTION_KEY = "CONTEXT_TRANSACTIONS";
private const string SESSION_KEY = "CONTEXT_SESSIONS";

public bool HasOpenTransactionOn()
{
    return HasOpenTransactionOn(DefaultConfigFile);
}

public void CommitTransactionOn()
{
    CommitTransactionOn(DefaultConfigFile);
}

public void CloseSessionOn()
{
    CloseSessionOn(DefaultConfigFile);
}

public void ForceCloseSessionOn()
{
    ForceCloseSessionOn(DefaultConfigFile);

}

public void ForceCloseSessionOn(string sessionFactoryConfigPath)
{
    ISession session;
    if (ContextSessions.TryGetValue(sessionFactoryConfigPath, out session))
    {
        if (session.IsOpen)
        {

            session.Close();
        }
        ContextSessions.Remove(sessionFactoryConfigPath);

    }
}

public void BeginTransactionOn()
{
    this.BeginTransactionOn(DefaultConfigFile);
}

public void RollbackTransactionOn()
{
    this.RollbackTransactionOn(DefaultConfigFile);
}

}

Хорошая вещь. Используя NH 3.2, он отлично работает с одним модом: мне пришлось заменить HasOpenTransactionOn, чтобы использовать transaction.IsActive. Вот почему.

Evan Haas 16.02.2012 08:26

В прошлом у меня был большой успех, используя модули поддержки NHibernate Spring.NET. См. http://www.springframework.net/downloads/Spring.Data.NHibernate/. Вы должны иметь возможность использовать модуль OpenSessionInView и расширять свои DAO из NHibernateSupport DAO, чтобы получить полную поддержку управления открыть сеанс в шаблоне просмотра.

Кроме того, хотя я никогда этого не пробовал, вы сможете использовать указанную выше структуру, даже если откажетесь от сброса предложений Spring.NET (а именно IoC и AOP).

Два предложения:

  • HybridSessionBuilder Джеффри Палермо (jeffreypalermo.com/blog/use-this-nhibernate-wrapper-to-keep-your-repository-classes-simple)
  • См. Примеры кода (в частности, Сессию 13) в Summer of NHibernate (www.summerofnhibernate.com)

Возможно, вам стоит подумать о том, чтобы ваш DAL меньше беспокоился об управлении сеансами NHibernate, используя NHibernate.Burrow (или реализовав аналогичный шаблон самостоятельно).

«NHibernate.Burrow - это легкое промежуточное программное обеспечение, разработанное для поддержки .Net-приложений, использующих NHibernate, путем предоставления расширенного и интеллектуального управления сеансами / транзакциями и других средств».

Если вы решите попробовать свои силы, внизу этой страницы есть несколько полезных ссылок:

Полезным поисковым запросом в Google может быть «NHibernate Session Management» и «Contextual Sessions» ...

Нет недостатка в идеях - можно сказать, что есть слишком много вариантов, надеюсь, мнение начнет тяготеть к Берроу или чему-то в этом роде ...

Другие вопросы по теме