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

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

Ответы [ 9 ]

17 голосов
/ 22 ноября 2008

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

Билли также работает над новым фреймворком, который использует 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);
}

}

5 голосов
/ 23 ноября 2008

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

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

4 голосов
/ 23 ноября 2008

Рекомендую проверить Ayende Rhino Commons . Документация на данный момент немного скудна, но как только вы начнете работать, работа с NHibernate станет НАМНОГО проще.

2 голосов
/ 27 ноября 2008

Я написал в блоге сообщение , в котором я использую управляемую веб-реализацию контекстной обработки сеансов. Может быть, это то, что вы ищете?

1 голос
/ 29 мая 2009

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

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

Конечно, это то, что я использовал, когда начинал работать с 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 InvalidOperationException("NHibernate configuration is null.");
}

config.AddAssembly("My.Assembly.Here");
factory = config.BuildSessionFactory();

if (factory==null)
{
throw new InvalidOperationException("Call to Configuration.BuildSessionFactory() returned null.");
}

session = factory.OpenSession();

if (session==null)
{
throw new InvalidOperationException("Call to factory.OpenSession() returned null.");
}

return session;
    }
} 

Дайте мне знать, если это поможет.

0 голосов
/ 21 июля 2009

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

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

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

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

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

0 голосов
/ 14 января 2009

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

0 голосов
/ 22 ноября 2008

Спасибо! Это полезно, но я ищу что-то более надежное.

Например, ссылка на сайте NH (http://hibernate.org/363.html#A9) - это вклад Эндрю Майорова, и он публикует три файла, например: (http://nhibernate.sourceforge.net/contrib/Wiki_AndrewMayorovAspNet.zip).

Дело в том, что это не очень помогает. Я не совсем уверен, как правильно его использовать. Я попробовал кое-что, но столкнулся с проблемой.

У кого-нибудь есть что-то, что использует это или подобное?

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