Spring.NET对NHibernate的封装

     最近在学习Spring.NET,对Spring.NET对NHibernate的封装用起来感觉很舒服,于是乎自己查看了Spring.NET的源代码,看看其秘密。

    用过NHibernate的童靴应该知道,我们想对数据库的进行CRUD操作,必须有Session,而Session又是由SessionFactory创造的,而SessionFactory可以由下面的代码创建。       

	var cfg = new NHibernate.Cfg.Configuration().Configure("Config/hibernate.cfg.xml");//hibernate.cfg.xml为配置文件
           using (ISessionFactory sessionFactory = cfg.BuildSessionFactory()) 
 	{ //创建Session
	   ISession session=sessionFactory.OpenSession()
 	   //CRUD操作
	}
	    	    	


    那在Spring.NET中如何操作呢?    先来看这段代码(Spring.NET源代码)

namespace Spring.Data.NHibernate.Generic.Support
{
    public abstract class HibernateDaoSupport : DaoSupport
    {
        public HibernateTemplate HibernateTemplate { get; set; }
        public ISessionFactory SessionFactory { get; set; }
        public ISession Session { get; }
        protected virtual HibernateTemplate CreateHibernateTemplate(ISessionFactory sessionFactory);
        protected override void CheckDaoConfig();
        protected ISession DoGetSession(bool allowCreate);
        protected DataAccessException ConvertHibernateAccessException(HibernateException ex);
        protected void ReleaseSession(ISession session);
    }
}


    这是一个抽象类,其中有一些重要属性:HibernateTemplate 、SessionFactory 、Session 。我们首先可以继承这个抽象类,具体如下   

 public abstract class RepositoryBase<T> : HibernateDaoSupport, IRepository<T> where T : class
    {
         /// <summary>
        /// 保存
         /// </summary>
        /// <param name="entity">实体</param>
        /// <returns></returns>
        public virtual object Save(T entity)
        {
            return this.HibernateTemplate.Save(entity);
        }

         /// <summary>
        /// 获取所有记录
        /// </summary>
        /// <returns></returns>
        public virtual IQueryable<T> LoadAll()
        {
            var result = Session.Query<T>();
            return result;
        }
	//...省略
    }	         

那上面的HibernateTemplate 、Session 从哪来呢?我们可以通过属性注入(参照刘冬的博客)的方式来设置。以下是配置文件:

  <!--SessionFactory对象-->
  <object id="NHibernateSessionFactory" type="Spring.Data.NHibernate.LocalSessionFactoryObject, Spring.Data.NHibernate30">
    <property name="DbProvider" ref="DbProvider"/>
    <property name="MappingAssemblies">
      <list>
        <value>DomainModel</value>
      </list>
    </property>
    <property name="HibernateProperties">
      <dictionary>
        <entry key="hibernate.current_session_context_class"
               value="Spring.Data.NHibernate.SpringSessionContext, Spring.Data.NHibernate30"/>

        <entry key="hibernate.connection.provider"
               value="NHibernate.Connection.DriverConnectionProvider"/>
        <!--数据库方言-->
        <entry key="dialect" value="${dialect}"/>

        <!--数据库驱动-->
        <entry key="connection.driver_class" value="${driver_class}"/>

        <entry key="use_outer_join" value="true"/>
        <entry key="show_sql" value="false"/>
        <!--自动建表(反向映射)-->
        <entry key="hbm2ddl.auto" value="${hbm2ddl.auto}"/>
        <!--超时时间-->
        <entry key="command_timeout" value="60"/>
        <entry key="query.substitutions" value="true 1, false 0, yes 'Y', no 'N'"/>
        <entry key="proxyfactory.factory_class"
               value="NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu"/>

      </dictionary>
    </property>
    <property name="ExposeTransactionAwareSessionFactory" value="true" />
  </object>
  <!--HibernateTemplate模板-->
  <object id="HibernateTemplate" type="Spring.Data.NHibernate.Generic.HibernateTemplate">
    <property name="SessionFactory" ref="NHibernateSessionFactory" />
    <property name="TemplateFlushMode" value="Auto" />
    <property name="CacheQueries" value="true" />
  </object>


    这样一来我们就有了HibernateTemplate和SessionFactory,有童靴就问了但是没有Session啊。是的,但是Session是不是可以由SessionFactory创建。我们具体再来看HibernateDaoSupport类下的Session属性(Spring.NET源代码):   

       public ISession Session
	    {
	        get
	        {
                return DoGetSession(HibernateTemplate.AllowCreate);
	        }
	    }


    再转到DoGetSession方法:   

 protected ISession DoGetSession(bool allowCreate)
        {
            return (!allowCreate ?
                SessionFactoryUtils.GetSession(SessionFactory, false) :
                    SessionFactoryUtils.GetSession(
                            SessionFactory,
                            this.hibernateTemplate.EntityInterceptor,
                            this.hibernateTemplate.AdoExceptionTranslator));
        }


再转到SessionFactoryUtils.GetSession()方法,(注:下面的方法为重载方法)

     private static ISession GetSession(
            ISessionFactory sessionFactory, IInterceptor entityInterceptor,
            IAdoExceptionTranslator adoExceptionTranslator, bool allowCreate)
        {
            try
            {
                return DoGetSession(sessionFactory, entityInterceptor, adoExceptionTranslator, allowCreate);
            }
            catch (HibernateException ex)
            {
                throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
            }
        }


继续转到SessionFactoryUtils.DoGetSession()方法,注意和上面的 DoGetSession()方法区分

    private static ISession DoGetSession(
            ISessionFactory sessionFactory, IInterceptor entityInterceptor,
            IAdoExceptionTranslator adoExceptionTranslator, bool allowCreate)
        {
            AssertUtils.ArgumentNotNull(sessionFactory, "sessionFactory", "SessionFactory can not be null");

            SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.GetResource(sessionFactory);
            if (sessionHolder != null && !sessionHolder.IsEmpty) 
            {
                // pre-bound Hibernate Session
                ISession session = null;
                if (TransactionSynchronizationManager.SynchronizationActive &&
                    sessionHolder.DoesNotHoldNonDefaultSession)
                {
                    // Spring transaction management is active ->
                    // register pre-bound Session with it for transactional flushing.
                    session = sessionHolder.ValidatedSession;
                    if (session != null && !sessionHolder.SynchronizedWithTransaction) 
                    {
                        log.Debug("Registering Spring transaction synchronization for existing Hibernate Session");
                        TransactionSynchronizationManager.RegisterSynchronization(
                            new SpringSessionSynchronization(sessionHolder, sessionFactory, adoExceptionTranslator, false));
                        sessionHolder.SynchronizedWithTransaction = true;
                        // Switch to FlushMode.AUTO if we're not within a read-only transaction.
                        FlushMode flushMode = session.FlushMode;
                        if (FlushMode.Never == flushMode &&
                            !TransactionSynchronizationManager.CurrentTransactionReadOnly) 
                        {
                            session.FlushMode = FlushMode.Auto;
                            sessionHolder.PreviousFlushMode = flushMode;
                        }
                    }
                }
                else
                {
                   // No Spring transaction management active -> simply return default thread-bound Session, if any
                   // (possibly from OpenSessionInViewModule)
                    session = sessionHolder.ValidatedSession;
                }
                
                if (session != null) 
                {
                    return session;
                }
                
            }


            ISession sess = OpenSession(sessionFactory, entityInterceptor);
            // Set Session to FlushMode.Never if we're within a read-only transaction.
            // Use same Session for further Hibernate actions within the transaction.
            // Thread object will get removed by synchronization at transaction completion.
            if (TransactionSynchronizationManager.SynchronizationActive) 
            {
                log.Debug("Registering Spring transaction synchronization for new Hibernate Session");
                SessionHolder holderToUse = sessionHolder;
                if (holderToUse == null) 
                {
                    holderToUse = new SessionHolder(sess);
                }
                else 
                {
                    holderToUse.AddSession(sess);
                }
                if (TransactionSynchronizationManager.CurrentTransactionReadOnly) 
                {
                    sess.FlushMode = FlushMode.Never;
                }
                TransactionSynchronizationManager.RegisterSynchronization(
                    new SpringSessionSynchronization(holderToUse, sessionFactory, adoExceptionTranslator, true));
                holderToUse.SynchronizedWithTransaction = true;
                if (holderToUse != sessionHolder) 
                {
                    TransactionSynchronizationManager.BindResource(sessionFactory, holderToUse);
                }
            }

            

            // Check whether we are allowed to return the Session.
            if (!allowCreate && !IsSessionTransactional(sess, sessionFactory)) 
            {
                CloseSession(sess);
                throw new InvalidOperationException ("No Hibernate Session bound to thread, " +
                    "and configuration does not allow creation of non-transactional one here");
            }

            return sess;


        }


    到此终于把Session找出来了。

    现在又有问题了,HibernateTemplate怎么有Save()、Load()等方法呢,它又是如何操作数据的(根据NHibernate的经验,它最后肯定和Session有关系)。通过看源代码会发现所有的方法(Save()、Load()等方法)都是调用public object Execute(IHibernateCallback action, bool exposeNativeSession)这个方法,这个方法下有这一句:

 Object result = action.DoInHibernate(sessionToExpose);

这里用到了一个设计模式--策略模式:

GetByTypeHibernateCallback、SaveObjectHibernateCallback等等都是继承自IHibernateCallback ,这里我们举SaveObjectHibernateCallback.DoInHibernate这个例子

        public object DoInHibernate(ISession session)
        {
            outer.CheckWriteOperationAllowed(session);
            return session.Save(entity);
        }

看看果然用到了Session,这下原理也就明白了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值