Terry's blog

Focus on bigdata and cloud.

博客园 首页 新随笔 联系 订阅 管理

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

posted on 2007-08-14 10:11  王晓成  阅读(185)  评论(0编辑  收藏  举报