此项目名字叫Cuyahoga,是一个CMS。该项目中就使用了NHibernate0.6作为持久层。并且使用了NHibernate0.6新添加的Lazy loading特性,是学习使用NHibernate的上佳例子。 下面是对他的一些评价: - Use the HttpContext to store your NHibernate session facade. This is what I call the HttpContext Local Session pattern 8-) 使用HttpContext .Item来存储NH的Session,亦即使用了HttpRequest--Session的模式 - Access to the session facade is provided by a property get in your overrided ASP.NET page's base class, such as "base.GetCoreRepository.LoadObjectById(..)". This is an alternative to having the repository itself control instantiation such as "CoreRepository.Instance.LoadObjectById(..)" CoreRepository就是一个数据访问逻辑组件了,对Session进行了管理,并且提供数据持久化的方法。部分代码如下:
public class CoreRepository { private ISessionFactory _factory; private ISession _activeSession; /**//// <summary> /// Get the active NHibernate session. /// </summary> public ISession ActiveSession { get { return this._activeSession; } } /**//// <summary> /// Create a repository for core objects. /// </summary> public CoreRepository() : this(false) { } /**//// <summary> /// Create a repository for core objects. /// </summary> /// <param name="openSession">Indicate if the CoreRepository should open a session and keep it in memory.</param> public CoreRepository(bool openSession) { this._factory = SessionFactory.GetInstance().GetNHibernateFactory(); if (openSession) { this._activeSession = this._factory.OpenSession(); } } /**//// <summary> /// Open a NHibernate session. /// </summary> public void OpenSession() { if (this._activeSession == null || ! this._activeSession.IsOpen) { this._activeSession = this._factory.OpenSession(); } else { throw new InvalidOperationException("The repository already has an open session"); } } /**//// <summary> /// Flushes the current active NHibernate session. /// </summary> public void FlushSession() { if (this._activeSession != null && this._activeSession.IsOpen) { this._activeSession.Flush(); } } /**//// <summary> /// Close the active NHibernate session /// </summary> public void CloseSession() { if (this._activeSession != null && this._activeSession.IsOpen) { this._activeSession.Close(); } } Generic methods#region Generic methods /**//// <summary> /// Generic method for retrieving single objects by primary key. /// </summary> /// <param name="type"></param> /// <param name="id"></param> /// <returns></returns> public object GetObjectById(Type type, int id) { if (this._activeSession != null) { return this._activeSession.Load(type, id); } else { throw new NullReferenceException("The repository doesn't have an active session"); } } /**//// <summary> /// Get all objects of a given type. /// </summary> /// <param name="type"></param> /// <returns></returns> public IList GetAll(Type type) { return GetAll(type, null); } /**//// <summary> /// Get all objects of a given type and add one or more names of properties to sort on. /// </summary> /// <param name="type"></param> /// <param name="sortProperties"></param> /// <remarks>Sorting is Ascending order. Construct a specific query/method when the sort order /// should be different.</remarks> /// <returns></returns> public IList GetAll(Type type, params string[] sortProperties) { ICriteria crit = this._activeSession.CreateCriteria(type); if (sortProperties != null) { foreach (string sortProperty in sortProperties) { crit.AddOrder(Order.Asc(sortProperty)); } } return crit.List(); } /**//// <summary> /// Generic method to insert an object. /// </summary> /// <param name="obj"></param> public void SaveObject(object obj) { ITransaction trn = this._activeSession.BeginTransaction(); try { // Try to find a UpdateTimestamp property and when found, set it to the current date/time. PropertyInfo pi = obj.GetType().GetProperty("UpdateTimestamp"); if (pi != null) { pi.SetValue(obj, DateTime.Now, null); } this._activeSession.Save(obj); trn.Commit(); } catch (Exception ex) { trn.Rollback(); throw ex; } } /**//// <summary> /// Generic method to update an object. /// </summary> /// <param name="obj"></param> public void UpdateObject(object obj) { ITransaction trn = this._activeSession.BeginTransaction(); try { this._activeSession.Update(obj); trn.Commit(); } catch (Exception ex) { trn.Rollback(); throw ex; } } /**//// <summary> /// Delete a specific object. Settings in the mapping file determine if this cascades /// to related objects. /// </summary> /// <param name="obj"></param> public void DeleteObject(object obj) { ITransaction trn = this._activeSession.BeginTransaction(); try { this._activeSession.Delete(obj); trn.Commit(); } catch (Exception ex) { trn.Rollback(); throw ex; } } /**//// <summary> /// Attach potentially stale objects to the current NHibernate session. This is required /// when objects are cached in the ASP.NET cache and they contain lazy loaded members. /// </summary> /// <param name="obj"></param> public void AttachObjectToCurrentSession(object obj) { if (this._activeSession != null) { if (this._activeSession.IsOpen) { this._activeSession.Update(obj); } else { throw new InvalidOperationException("The current NHibernate session is not open, so no objects can be attached."); } } else { throw new NullReferenceException("No active NHibernate session available to attach the object to."); } } /**//// <summary> /// Mark an object for deletion. Commit the deletion with Session.Flush. /// </summary> /// <param name="obj"></param> public void MarkForDeletion(object obj) { this._activeSession.Delete(obj); } #endregion }- A new NHibernate Open Session at beginning of a web request and close it at the end of the request. This is the "session-per-request" pattern. - Using a custom IHttpModule called NHSessionModule to provide the handlers for Context_BeginRequest and Context_EndRequest. This is a nice way of automatically wiring up your creation/opening and closing and sessions. 使用了一个HttpModule 来进行Session的存储和获得,代码如下:
using System; using System.Web; using Cuyahoga.Core.Service; namespace Cuyahoga.Web.Util { 在一个HTTP Request期间管理NHibetnate的Session#region 在一个HTTP Request期间管理NHibetnate的Session /**//// <summary> /// Http module that manages the NHibernate sessions during an HTTP Request. /// </summary> public class NHSessionModule : IHttpModule { /**//// <summary> /// Default constructor. /// </summary> public NHSessionModule() { } public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(Context_BeginRequest); context.EndRequest += new EventHandler(Context_EndRequest); } public void Dispose() { // Nothing here } private void Context_BeginRequest(object sender, EventArgs e) { // Create the repository for Core objects and add it to the current HttpContext. CoreRepository cr = new CoreRepository(true); HttpContext.Current.Items.Add("CoreRepository", cr); } private void Context_EndRequest(object sender, EventArgs e) { // Close the NHibernate session. if (HttpContext.Current.Items["CoreRepository"] != null) { CoreRepository cr = (CoreRepository)HttpContext.Current.Items["CoreRepository"]; cr.CloseSession(); } } } #endregion }也就是将session保存到HttpContext.Current.Items中,这样做的好处请看这里。 NHibernate中添加的最重要的特性就是用proxy对延迟加载的支持(包括对集合的和单个object的延迟加载),这也是因为项目中使用了动态代理技术(这要求业务实体的成员需要是virtual的或者实现某个接口), 这为多表的join带来了性能上的提升。