移植 Castle 的 ActiveRecord 直接为 NHibernate 所用

阅读更多

         在动手写这篇 Post 之前我得先声明一下,本人对 Castle 的了解还不够深入,仅仅在近期在项目中使用过而已,所以我的做法不一定是正确的,也不一定能给大家带来帮助,说不定还会给你带来更多的麻烦

         把 Posts 发到首页上也是希望大家都能说出自己的想法,还有我的处理方式的可行性做一些分析和批评。


         从对 Castle  一无所知到有所了解,Terrylee 的  Castle 开发系列(推荐) 给了我很大的帮助,特在此对 Terrylee 表示感谢。

         对于我自己而言我并不太喜欢 Castle 封装 NHibernate 的方式, 虽然减少了配置映射文件的复杂性和易出错,但我还是更喜欢把映射文件和实体类分开来,我觉得这更加直观,看起来也不会太凌乱,唯一的缺点就是有时候会顾此失彼,但我认为这是值得的。就好比是 ASP.NET 将界面和代码相分离,但萝卜青菜各有所爱,我们所要做的就是像找女朋友一样选自己喜欢的。

         Castle 把 ActiveRecordBase 声明为 abstract 以至于在实体类直接继承并实现一些自操作行为,如 Save()、 Create()、Update()、Delete() 也是我深恶痛绝日,我非常不喜欢把业务操作移殖到实体层去,层与层之间的职任应该划分得很清晰,要不然我看了就觉得不舒服,可能有人会说如果不喜欢我完全可以不去理会它,当它不存在就是了,但它却确确实实地存在着,还是 public ,无论走到那里都能看到自己不喜欢的东西我还能无动于衷吗?而且我们还有同样方便方法来代替,稍后将会讲到,所以我要把 ActiveRecordBase 改造成为 ActiveRecord 并且只留下静态方法,相当于一个 NHibernateHelper。

         至于 IOC 容器我更喜欢 Spring.Net,虽然比较复杂,但还是那句话,萝卜青菜各有所爱。

         接下来就开始我们的改造工作,首先是 Session 管理的问题,由于现在我没时间研究 Castle 的源码,加上水平有限,决定另寻它路。于是在  DDLLY命名空间 里找到了 NHibernate的Session管理,我承认通过 IHttpModule 来存储 Session 不失为了一个好方法,但它仅解决了客户端请求操作的问题,当请求来自服务器端的时候 HttpContext.Current 将为 NULL 值。我的解决方法是新建一个 SessionObject 类,类中两个属性,一个用于存储 Session 值,另一个用于标记操作完成后是否关闭 Session,当 HttpContext 为空时创建一个新的 SessionObject 实例并将其标记为需要 Close,这样做的缺点是每次操作都必须检查是否需要关闭 Session,但暂时还想不到更好的解决方法就先凑合着使用了。

         下面是我改造过后的代码,这个类并不能独立工作,它还依赖于其它类,在后面我会放上完整项目供下载。


namespace Yyw.DBUtility.NH.ActiveRecords
{
    
using System;
    
using System.Collections;
    
using System.Collections.Generic;
    
using NHibernate;
    
using NHibernate.Expression;
    
using Yyw.DBUtility.NHibernateSessionStorage;


    
/**//// 
    
/// Base class for all ActiveRecord classes. Implements 
    
/// all the functionality to simplify the code on the 
    
/// subclasses.
    
/// 

    [Serializable]
    
public class ActiveRecord
    
{

        
/**//// 
        
/// Constructs an ActiveRecordBase subclass.
        
/// 

        public ActiveRecord()
        
{
        }


        
static methods#region static methods

        
/**//// 
        
/// Invokes the specified delegate passing a valid 
        
/// NHibernate session. Used for custom NHibernate queries.
        
/// 

        
/// The target ActiveRecordType
        
/// The delegate instance
        
/// The ActiveRecord instance
        
/// Whatever is returned by the delegate invocation

        //public static object Execute(Type targetType, NHibernateDelegate call, object instance)
        
//{
        
//    if (targetType == null) throw new ArgumentNullException("targetType", "Target type must be informed");
        
//    if (call == null) throw new ArgumentNullException("call", "Delegate must be passed");

        
//    EnsureInitialized(targetType);

        
//    ISession session = _holder.CreateSession( targetType );

        
//    try
        
//    {
        
//        return call(session, instance);
        
//    }
        
//    catch(Exception ex)
        
//    {
        
//        throw new ActiveRecordException("Error performing Execute for " + targetType.Name, ex);
        
//    }
        
//    finally
        
//    {
        
//        _holder.ReleaseSession(session);
        
//    }
        
//}

        
/**//// 
        
/// Finds an object instance by a unique ID
        
/// 

        
/// The AR subclass type
        
/// ID value
        
/// true if you want to catch an exception 
        
/// if the object is not found
        
/// 
        
/// if throwOnNotFound is set to 
        
/// true and the row is not found

        public static T FindByPrimaryKey<T>(object id, bool throwOnNotFound) where T : class
        
{
            SessionObject sessionObj 
= NHibernateDatabaseFactory.CreateSession();

            ISession session 
= sessionObj.Session;

            
try
            
{
                
return session.Load<T>( id );
            }

            
catch(ObjectNotFoundException ex)
            
{
                
if (throwOnNotFound)
                
{
                    String message 
= String.Format("Could not find {0} with id {1}"typeof(T).Name, id);
                    
throw new NotFoundException(message, ex);
                }


                
return default(T);
            }

            
catch(Exception ex)
            
{
                
throw new ActiveRecordException("Could not perform Load (Find by id) for " + typeof(T).Name, ex);
            }

            
finally
            
{
                
if (sessionObj.IsNeedClose)
                    session.Close();
            }
        
        }


        
/**//// 
        
/// Finds an object instance by a unique ID
        
/// 

        
/// The AR subclass type
        
/// ID value
        
/// 

        public static T FindByPrimaryKey<T>(object id) where T : class
        
{
            
return FindByPrimaryKey<T>(id, true);
        }


        
/**//// 
        
/// Returns all instances found for the specified type.
        
/// 

        
/// 
        
/// 

        public static IList<T> FindAll<T>() where T : class
        
{
            
return FindAll<T>((Order[]) null);
        }


        
/**//// 
        
/// Returns a portion of the query results (sliced)
        
/// 

        public static IList<T> SlicedFindAll<T>(int firstResult, int maxresults, Order[] orders, params ICriterion[] criterias) where T : class
        
{
            SessionObject sessionObj 
= NHibernateDatabaseFactory.CreateSession();

            ISession session 
= sessionObj.Session;

            
try
            
{
                ICriteria criteria 
= session.CreateCriteria(typeof(T));

                
foreach( ICriterion cond in criterias )
                
{
                    criteria.Add( cond );
                }

你可能感兴趣的:(ActiveRecord,ASP.net,C#,C++,C)