• NHibernate初学体验进阶篇


     

    xchuntao@163.com QQ:23106676

    在上篇NHibernate初学体检记》中,我参照NHibernate官方快速指南写了两个示例项目,在示例2的源码中充斥了如下类似的代码:

                Configuration cfg = new Configuration();

                cfg.AddAssembly("NHibernate.Examples");

                ISessionFactory factory = cfg.BuildSessionFactory();

                ISession session = factory.OpenSession();

                ITransaction transaction = session.BeginTransaction();

     

    如何解决这个问题呢?答案就是采用DAOData Access Object)模式。

     

    一、编写DAO

    DAO其实就是把对实体的基本CRUD(创建、读取、更新、删除)操作进行封装。在本示例中也就是把对User实体的持久化操作进行封装,看下代码就什么都清楚了(相比以前的简单代码,我又加入了异常处理部分J):

    public class UserDAO

        {

            private ISession session;

            private ITransaction tx;

     

            public void Create(User newUser)

            {

                try

                {

                    StartOperation();

                    session.Save(newUser);

                    tx.Commit();

                }

                catch (HibernateException e)

                {

                    HandleException(e);

                }

                finally

                {

                    session.Close();

                }

            }

     

            public void Update(User newUser)

            {

                try

                {

                    StartOperation();

                    session.Update(newUser);

                    tx.Commit();

                }

                catch (HibernateException e)

                {

                    HandleException(e);

                }

                finally

                {

                    session.Close();

                }

            }

     

            public void Delete(User user)

            {

                try

                {

                    StartOperation();

                    session.Delete(user);

                    tx.Commit();

                }

                catch (HibernateException e)

                {

                    HandleException(e);

                }

                finally

                {

                    session.Close();

                }

            }

     

            public User Find(string id)

            {

                User user = null;

                try

                {

                    StartOperation();

                    user = session.Get<User>(id);

                    tx.Commit();

                }

                catch (HibernateException e)

                {

                    HandleException(e);

                }

                finally

                {

                    session.Close();

                }

     

                return user;

            }

     

            public IList FindAll()

            {

                IList userList = null;

                try

                {

                    StartOperation();

                    userList = session.CreateCriteria(typeof(User)).List();

                    tx.Commit();

                }

                catch (HibernateException e)

                {

                    HandleException(e);

                }

                finally

                {

                    session.Close();

                }

                return userList;

            }

     

            //---------------------------------------------------

            private void StartOperation()

            {

                Configuration cfg = new Configuration();

                cfg.AddAssembly("NHibernate. Examples");

     

                ISessionFactory factory = cfg.BuildSessionFactory();

     

                session = factory.OpenSession();

                tx = session.BeginTransaction();

            }

     

            private void HandleException(HibernateException e)

            {

                tx.Rollback();

                throw e;

                //注:你可以在此写自己的异常处理,如记录日志...

            }

        }

     

    有了UserDAO我们对User实体的操作简化为简单的两行代码(如下添加用户的示例):

    User newUser = new User();

                newUser.Id = txtLogonID.Text.Trim();

                newUser.UserName = txtName.Text.Trim();

                newUser.Password = txtPassword.Text.Trim();

                newUser.EmailAddress = txtEmailAddress.Text.Trim();

                newUser.LastLogon = DateTime.Now;

                //----------------------------------------------------

                UserDAO userDAO = new UserDAO();

                userDAO.Create(newUser);

     

    NHibernate的那些充斥期间的初始化和收尾代码不见了,DAO模式明显降低了应用程序与NHibernate的耦合度。看起来不错J,不过,这里有潜在的重复问题:我们的示例比较简单,只有一个User实体类,正常的项目中会有大量这样的的实体类,也就会有大量对应的DAO类,我们的“复制/粘贴”恶梦开始了,你要为所有的DAO类编写类似于UserDAO类的代码,这里面明显有很多的重复,我们再写其它的DAO类时,需要改变的仅仅是实体类,其余代码都是“复制/粘贴”来的。“复制/粘贴”----所有编程问题的根源!(摘自《Hibernate Quickly中文版》P149)。这时候我们就需要“抽象”了!(突然觉得“抽象”是不是“抽出那些相象的部分”之意,哈哈!)

     

    二、抽象DAO

    我们来创建一个抽象的DAOAbstractDAO,作为超类,让其它的DAO继承之。AbstractDAO封装那些“相象”的部分,以简化实体DAO的编写。看代码吧:

    public abstract class AbstractDAO

        {

            private ISession session;

            private ITransaction tx;

     

            protected void Save(Object obj)

            {

                try

                {

                    StartOperation();

                    session.Save(obj);

                    tx.Commit();

                }

                catch (HibernateException e)

                {

                    HandleException(e);

                }

                finally

                {

                    session.Close();

                }

            }

     

            protected void Update(Object obj)

            {

                try

                {

                    StartOperation();

                    session.Update(obj);

                    tx.Commit();

                }

                catch (HibernateException e)

                {

                    HandleException(e);

                }

                finally

                {

                    session.Close();

                }

            }

     

            protected void Delete(Object obj)

            {

                try

                {

                    StartOperation();

                    session.Delete(obj);

                    tx.Commit();

                }

                catch (HibernateException e)

                {

                    HandleException(e);

                }

                finally

                {

                    session.Close();

                }

            }

     

            protected Object Find(System.Type clazz, Object id)

            {

                Object obj = null;

                try

                {

                    StartOperation();

                    obj = session.Get(clazz,id);

                    tx.Commit();

                }

                catch (HibernateException e)

                {

                    HandleException(e);

                }

                finally

                {

                    session.Close();

                }

     

                return obj;

            }

     

            protected IList FindAll(System.Type clazz)

            {

                IList objList = null;

                try

                {

                    StartOperation();

                    objList = session.CreateCriteria(clazz).List();

                    tx.Commit();

                }

                catch (HibernateException e)

                {

                    HandleException(e);

                }

                finally

                {

                    session.Close();

                }

     

                return objList;

            }       

     

           

     

            //---------------------------------------------------

            private void StartOperation()

            {

                Configuration cfg = new Configuration();

                cfg.AddAssembly("NHibernate. Examples");           

                ISessionFactory factory = cfg.BuildSessionFactory();

                session = factory.OpenSession();          

                tx = session.BeginTransaction();

            }

     

            private void HandleException(HibernateException e)

            {

                tx.Rollback();

                throw e;

                //注:你可以在此写自己的异常处理,如记录日志...

            }

        }

     

    我们将通用的CRUD方法(包括save/update/delete/find)都放到了AbstractDAO类中,并将这些方法设为protected,这样只有子类可调用它们。看看我们现在继承自AbstractDAOUserDAO是不是简化了:

        public class UserDAO : AbstractDAO

        {

            public void Create(User newUser)

            {

                base.Save(newUser);

            }

     

            public void Update(User newUser)

            {

                base.Update(newUser);

            }

     

            public void Delete(User user)

            {

                base.Delete(user);

            }

     

            public User Find(string id)

            {

                return (User)base.Find(typeof(User), id);

            }

     

            public IList FindAll()

            {

                return (IList)base.FindAll(typeof(User));

            }            

     

        }

     

    哈哈,UserDAO中该有的有,不该有的没有了,世界看起来清爽多了!呼吸下新鲜的空气吧,不用为写更多的实体DAO类发愁了(如果还有代码自动生成工具那就更好了----懒惰的程序员,呵呵J)!

    (补注:虽然编写实体DAO类代码简化了许多,但是这些实体DAO还是非常的相似,重复性还是很大的,通过设计泛型的AbstractDAO可以不用写具体的实体DAO了,太棒了!请参考文后评论中的6楼10楼的内容.)

        不过,不要高兴的太早,还没完呢!

     

    三、提高效率(引入单例模式)

    看看AbstractDAO中每个CRUD方法都要调用的函数StartOperation()它包含创建ISessionFactory对象的核心代码,这个创建过程需要加载NHibernate映射文件信息,内存开销非常大,每个CRUD方法都要进行重复的创建,这还得了!还好我们有Singleton(单例模式)对付他!Singleton保证了一个类只被实例化一次,它将避免我们的重复加载映射文件信息的问题。以下是我们的实现:

    public sealed class NHibernateFactory

        {

            private static volatile ISessionFactory factory;

            private static object syncRoot = new Object();

            private NHibernateFactory() { }

     

            public static ISessionFactory BuildIfNeeded()

            {

                if (factory == null)

                {

                    lock (syncRoot)

                    {

                        if (factory == null)

                        {

                            Configuration cfg = new Configuration();

                            cfg.AddAssembly("NHibernate. Examples");

                            factory = cfg.BuildSessionFactory();

                        }

                    }

                }

                return factory;

            }

     

            //----------------------------------

            static public ISession OpenSession()

            {

                NHibernateFactory.BuildIfNeeded();

                ISession session = factory.OpenSession();

                return session;

            }

        }

     

    (注:本实现参考了MSDNhttp://msdn2.microsoft.com/zh-cn/library/ms998558.aspx 《在 C# 中实现 Singleton》中的内容,有关Singleton或更多设计模式推荐阅读《大话设计模式》一书,很适合初学者的一本好书!)

    有了单例的NHibernateFactory,我们的StartOperation()将变为:

    private void StartOperation()

            {

                session = NHibernateFactory.OpenSession();

                tx = session.BeginTransaction();

            }

     

    啊哈,恭喜你成功进阶!

     

    听说SpringHibernate有更好的封装,那么Spring.NET中应该也有对NHibernate的封装吧,有空再说J

     

    注:本文内容参考了《Hibernate Quickly中文版》P144-154.

    文中内容不妥之处,敬请各位高手指教!

     

    本文示例源码下载:/Files/bluesky521/NHibernateQuickStart3.rar

    测试环境:单机安装Win2003SP2 + SQL2000 + .NET2.0 + VS2005

  • 相关阅读:
    Python
    Python
    Python
    Python
    Python
    Python
    Scala核心编程_第01章_Scala概述
    与富婆讨论性,死亡与生活的意义
    python邮件发送给多人时,只有第一个人能收到的问题
    少年维特的烦恼
  • 原文地址:https://www.cnblogs.com/SummerRain/p/1111889.html
Copyright © 2020-2023  润新知