此项目名字叫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带来了性能上的提升。