任何人都可以提供/引用适当的OO类型助手类来管理SessionFactory的单例,然后还管理Sessions吗?
查看Billy McCafferty的作品.他的早期版本有一些限制,你需要纠正关闭和刷新的错误处理,我不确定我是否正确,但我会发布我如何修改他的东西.
Billy还在开发一个使用MVC和nHibernate的新框架,名为S #arp Architechure,我目前正在使用它,到目前为止一直很好.
无论如何,这是我修改后的代码版本.我对准确性或完整性没有任何意义,你自己承担风险.如果您使用此功能,请确保关闭会话.如果您有任何问题,请发送电子邮件[joshua] [dot] [berke]在[gmail ...你知道其余的].
////// 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. /// public sealed class NHibernateSessionManager { private const string DefaultConfigFile = "DefaultAppWeb.Config"; private static readonly object _syncRoot = new object(); #region Thread-safe, lazy Singleton ////// This is a thread-safe, lazy singleton. See http://www.yoda.arachsys.com/csharp/singleton.html /// for more details about its implementation. /// public static NHibernateSessionManager Instance { get { return Nested.NHibernateSessionManager; } } ////// Private constructor to enforce singleton /// private NHibernateSessionManager() { } ////// Assists with ensuring thread-safe, lazy singleton /// private class Nested { static Nested() { } internal static readonly NHibernateSessionManager NHibernateSessionManager = new NHibernateSessionManager(); } #endregion ////// This method attempts to find a session factory stored in /// Path location of the factory config 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; } ////// via its name; if it can't be found it creates a new one and adds it the hashtable. /// /// 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(). /// 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); } ////// Gets or creates an ISession using the web / app config file. /// ///public ISession GetSessionFrom() { return GetSessionFrom(DefaultConfigFile, null); } /// /// Gets a session with or without an interceptor. This method is not called directly; instead, /// it gets invoked from other public methods. /// 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; } ////// Flushes anything left in the session and closes the connection. /// 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); } } ////// 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 /// private Dictionaryinstead of the WinForms specific . /// Discussion concerning this found at http://forum.springframework.net/showthread.php?t=572 /// ContextTransactions { get { if (IsInWebContext()) { if (HttpContext.Current.Items[TRANSACTION_KEY] == null) HttpContext.Current.Items[TRANSACTION_KEY] = new Dictionary (); return (Dictionary )HttpContext.Current.Items[TRANSACTION_KEY]; } else { if (CallContext.GetData(TRANSACTION_KEY) == null) CallContext.SetData(TRANSACTION_KEY, new Dictionary ()); return (Dictionary )CallContext.GetData(TRANSACTION_KEY); } } } /// /// 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 /// private Dictionaryinstead of the WinForms specific . /// Discussion concerning this found at http://forum.springframework.net/showthread.php?t=572 /// ContextSessions { get { if (IsInWebContext()) { if (HttpContext.Current.Items[SESSION_KEY] == null) HttpContext.Current.Items[SESSION_KEY] = new Dictionary (); return (Dictionary )HttpContext.Current.Items[SESSION_KEY]; } else { if (CallContext.GetData(SESSION_KEY) == null) CallContext.SetData(SESSION_KEY, new Dictionary ()); return (Dictionary )CallContext.GetData(SESSION_KEY); } } } private bool IsInWebContext() { return HttpContext.Current != null; } private Dictionary sessionFactories = new Dictionary (); 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); }
}
我过去使用Spring.NET的NHibernate支持模块取得了很大的成功.请参阅http://www.springframework.net/downloads/Spring.Data.NHibernate/.您应该能够使用OpenSessionInView模块并从NHibernateSupport DAO扩展您的DAO,以在视图模式中获得对打开会话的完全管理支持.
此外,虽然我从未尝试过,但即使您选择不重置Spring.NET的产品(即IoC和AOP),您也应该能够使用上述框架.