http://www.cnblogs.com/GoodHelper/archive/2011/02/17/1948744.html

NHibernate从入门到精通系列(4)——持久对象的生命周期(上)

 

  

  内容摘要

    持久对象的状态的概念

    持久对象的状态Demo

  一、持久对象的状态的概念  

  在NHibernate中有三种状态,对它的深入理解,才能更好的理解NHibernate的运行机理,刚开始不太注意这些概念,后来发现它是重要的。对于NHibernate和SQL的关系有更好的理解;对于理解需要持久化的.NET对象,在它的生命周期中三种状态之间的互相转化有很大帮助。如图1.1所示

图1.1

  • 临时态(Transient):用new创建的对象,它没有持久化,没有纳入Session中,随时可以被垃圾回收,处于此状态的对象叫临时对象。特点:数据库中没有与之对应的记录;
  • 持久态(Persistent):已经持久化,加入到了Session缓存中。通过NHibernate保存的对象或通过Get/Load等方法获取出的对象,其对象没有脱离Session的管理,处于此状态的对象叫持久对象;
  • 游离态(Detached):持久化对象脱离了Session的对象。如Session缓存被清空的对象。特点:已经持久化,但不在Session缓存中。处于此状态的对象叫游离对象;

  二、持久对象的状态Demo

  2.1 准备工作

  (1)建立名为“NHibernateTest”的项目

  (2)引用相应的程序集并引入上节课的“Domain”项目。

  (3)复制上节课的“hibernate.cfg.xml”配置模板

hibernate.cfg.xml

<?xml version="1.0" encoding="utf-8"?> <!-- This template was written to work with NHibernate.Test. Copy the template to your NHibernate.Test project folder and rename it in hibernate.cfg.xml and change it for your own use before compile tests in VisualStudio. --> <!-- This is the System.Data.dll provider for SQL Server --> <hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >     <session-factory name="NHibernateTest">         <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>         <property name="connection.connection_string">       server=.\SQLEXPRESS;database=NHibernateDemo;uid=sa;pwd=;     </property>         <property name="adonet.batch_size">10</property>         <property name="show_sql">true</property>         <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>         <property name="use_outer_join">true</property>         <property name="command_timeout">60</property>     <property name="hbm2ddl.auto">update</property>         <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>         <property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>     <mapping assembly="Domain"/>     </session-factory> </hibernate-configuration>

  (4)引用“log4net.dll”并配置App.config,用于输出日志 

  

App.config

<?xml version="1.0"?> <configuration>   <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />   </configSections>
  <!--log4net配置-->   <log4net debug="true">     <appender name="LogFileAppender" type="log4net.Appender.FileAppender">       <param name="File" value="Logs\Log.log" />       <param name="datePattern" value="MM-dd HH:mm" />       <param name="AppendToFile" value="true" />       <layout type="log4net.Layout.PatternLayout">         <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" />       </layout>     </appender>     <appender name="HttpTraceAppender" type="log4net.Appender.ASPNetTraceAppender">       <layout type="log4net.Layout.PatternLayout">         <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" />       </layout>     </appender>     <appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">       <layout type="log4net.Layout.PatternLayout">         <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" />       </layout>     </appender>     <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">       <param name="File" value="Logs/Log.log" />       <param name="AppendToFile" value="true" />       <param name="MaxSizeRollBackups" value="10" />       <param name="MaximumFileSize" value="100K" />       <param name="RollingStyle" value="Size" />       <param name="StaticLogFileName" value="true" />       <layout type="log4net.Layout.PatternLayout">         <param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n" />       </layout>     </appender>     <root>       <level value="ALL" />       <appender-ref ref="RollingLogFileAppender" />     </root>   </log4net>
  <startup>     <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>   </startup> </configuration>

  (5)复制“LinFu.DynamicProxy.dll”和“NHibernate.ByteCode.LinFu.dll”文件,粘贴到项目中。

  (6)增加用于单元测试的类文件“LifecycleTest.cs”

LifecycleTest.cs

    [TestFixture]     public class LifecycleTest     {         private ISessionFactory sessionFactory;
        public LifecycleTest()         {             log4net.Config.XmlConfigurator.Configure();         }
        [SetUp]         public void Init()         {             var cfg = new NHibernate.Cfg.Configuration().Configure("Config/hibernate.cfg.xml");             sessionFactory = cfg.BuildSessionFactory();         }      }

  如图2.1.1所示,准备完成后,便可以开始我们的演示。

图2.1.1

  2.2 临时态(Transient)到持久态(Persistent)

  先new一个对象,该对象的状态为Transient,然后调用Save()方法将该对象持久化到数据库中,该对象的状态变为Persistent。在未关闭Session前,修改该对象的属性,最后提交事务。

TransientToPersistentTest

        /// <summary>         /// 临时态-->持久态         /// </summary>         [Test]         public void TransientToPersistentTest()         {             using (ISession session = this.sessionFactory.OpenSession())             {                 using (ITransaction tran = session.BeginTransaction())                 {                     //Transient                     var product = new Product                     {                         ID = Guid.NewGuid(),                         BuyPrice = 10M,                         Code = "ABC123",                         Name = "电脑",                         QuantityPerUnit = "20x1",                         SellPrice = 11M,                         Unit = "台"                                             }; 
                    try                     {                         //Persistent                         session.Save(product);
                        //保存记录后修改数据,观察数据库中数据的变化                         product.SellPrice = 12M;
                        tran.Commit();                     }                     catch (Exception ex)                     {                         tran.Rollback();                         throw ex;                     }                 }             }         }

  运行效果如图2.2.1所示,首先生成了insert into语句,然后生成了update语句。

图2.2.1

  一开始,Product的SellPrice属性,我设置为“11M”,然后调用“Save”方法持久化“Product”对象,接下来修改SellPrice属性到“12M”。最后让我们打开数据库,看一下里面的数据到底是“11M”,还是“12M”。如图2.2.2所示,数据是“12M”。

图2.2.2

  这时,我们心里便产生了一个疑问:把Product的SellPrice属性从“11M”修改为“12M”后,并没有调用Save()或者Update()的方法,为什么数据库中的数据会变呢?

  这是因为,当对象处于Persistent状态,并没有脱离Session管理时,其属性发生改变后,数据库相对应的记录会与之同步

  2.3 持久态(Persistent)到游离态(Detached),再到持久态(Persistent)

PersistentToTestDetached

/// <summary>         /// 持久态-->游离态-->持久态         /// </summary>         [Test]         public void PersistentToTestDetached()         {             //Transient             var product = new Product             {                 ID = Guid.NewGuid(),                 BuyPrice = 10M,                 Code = "ABC123",                 Name = "电脑",                 QuantityPerUnit = "20x1",                 SellPrice = 11M,                 Unit = "台"             };
            using (ISession session = this.sessionFactory.OpenSession())             {                 using (ITransaction tran = session.BeginTransaction())                 {                                    try                     {                         //Persistent                         session.Save(product);                         product.SellPrice = 12M;
                        tran.Commit();                     }                     catch (Exception ex)                     {                         tran.Rollback();                         throw ex;                     }                 }             }
            //Detached             product.SellPrice = 13M;
            using (ISession session = this.sessionFactory.OpenSession())             {                 using (ITransaction tran = session.BeginTransaction())                 {                     try                     {                         //Persistent                         session.Update(product);                         tran.Commit();                     }                     catch (Exception ex)                     {                         tran.Rollback();                         throw ex;                     }                 }             }         }

  运行效果如图2.3.1所示。当对象处于游离态(Detached)时,修改其属性,是不会与数据库发生同步的。调用Update()方法后,对象则变回持久态(Persistent)。

图2.3.1

  2.4 Get方法得到持久态(Persistent)

  通过Get()方法获取持久态(Persistent)对象,然后修改其属性,观察是否与数据库发生同步。运行效果如图2.4.1所示,先生成insert into语句,然后生成select语句,最后生成update语句。

图2.4.1

  我们能够得出结论,通过Get()方法,是可以得到持久态(Persistent)对象的。

  2.5 Get和Load()方法的区别

  我们模拟一个数据库中不存在的对象,分别调用Get和Load()方法来测试产生的效果。

  

  Get方法的代码如下:

Get

        /// <summary>         /// 查询空记录         /// </summary>         [Test]         public void GetNullTest()         {             Guid id = Guid.NewGuid(); 
            using (ISession session = this.sessionFactory.OpenSession())             {                 using (ITransaction tran = session.BeginTransaction())                 {                     try                     {                         //Persistent                         var product = session.Get<Product>(id);
                        Console.WriteLine("调用 Get()方法");
                        //断言为空                         Assert.Null(product);
                        tran.Commit();                     }                     catch (Exception ex)                     {                         tran.Rollback();                         throw ex;                     }                 }             }         }

  Get()方法的运行效果,如图2.5.1所示。调用Get()方法后,数据库中不存在的对象返回值为null,并且一但调用Get()方法,就会生成SQL语句。

图2.5.1

  Load()方法的代码如下:

Load

      /// <summary>         /// 查询空记录         /// </summary>         [Test]         public void LoadTest()         {             Guid id = Guid.NewGuid();
            using (ISession session = this.sessionFactory.OpenSession())             {                 using (ITransaction tran = session.BeginTransaction())                 {                     try                     {                         //Persistent                         var product = session.Load<Product>(id);
                        Console.WriteLine("调用 Load()方法");
                        //断言为空                         Assert.NotNull(product);
                        //当查看其属性时,则会生成SQL语句                         string name = product.Name;                         Assert.NotNull(name);  //断言name不为空                         tran.Commit();                     }                     catch (Exception ex)                     {                         tran.Rollback();                         throw ex;                     }                 }             }         }

  Load()方法的运行效果,如图2.5.2所示。调用Load()方法查询数据库中不存在的对象,返回值不为空;当调用Load()方法时,不立刻产生SQL语句,查看其属性后才产生SQL语句,并且查看数据库中不存在对象的属性时会抛出异常。原因是调用Load()方法会返回一个“代理类”,这是NHibernate的一个重要的特性——延迟加载。

 延迟加载(lazy load)也叫“懒加载”,是NHibernate关联关系对象默认的加载方式,延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。可以简单理解为,只有在使用的时候,才会发出SQL语句进行查询。 延迟加载的有效期是在Session打开的情况下,当Session关闭后,会报异常。NHibernate的代理对象是由第三方组件“Antlr3.Runtime”提供的。

图2.5.2

  2.6 Delete()方法

  先得到一个持久态(Persistent)对象,然后调用Delete()方法删除该对象,这时该对象变回临时态(Transient)

  代码如下:

Delete

        [Test]         public void DeleteTest()         {             using (ISession session = this.sessionFactory.OpenSession())             {                 using (ITransaction tran = session.BeginTransaction())                 {                     //Transient                     var product = new Product                     {                         ID = Guid.NewGuid(),                         BuyPrice = 10M,                         Code = "ABC123",                         Name = "电脑",                         QuantityPerUnit = "20x1",                         SellPrice = 11M,                         Unit = "台"
                    };
                    try                     {                         //Persistent                         session.Save(product);
                        //Transient                         session.Delete(product);
                        tran.Commit();                     }                     catch (Exception ex)                     {                         tran.Rollback();                         throw ex;                     }                 }             }         }

  运行效果如图2.6.1所示,先生成insert into语句,再生成delete语句。

图2.6.1

  2.7 Update()方法

  先手动打造new一个数据库中存在的游离态(Detached)对象,然后直接调用Update()方法将对象的状态设置为持久态(Persistent)

  代码如下:

Update

        [Test]         public void UpdateTest()         {             Guid id = Guid.NewGuid();
            using (ISession session = this.sessionFactory.OpenSession())             {                             using (ITransaction tran = session.BeginTransaction())                 {                     //Transient                     var product = new Product                     {                         ID = id,                         BuyPrice = 10M,                         Code = "ABC123",                         Name = "电脑",                         QuantityPerUnit = "20x1",                         SellPrice = 11M,                         Unit = "台"
                    };
                    try                     {                         //Persistent                         session.Save(product);                         tran.Commit();                     }                     catch (Exception ex)                     {                         tran.Rollback();                         throw ex;                     }                 }             }
            using (ISession session = this.sessionFactory.OpenSession())             {                 using (ITransaction tran = session.BeginTransaction())                 {                     //Detached                     var product = new Product                     {                         ID = id,                         Code = "ABC456",                     };
                    try                     {                         //Persistent                         session.Update(product);
                        tran.Commit();                     }                     catch (Exception ex)                     {                         tran.Rollback();                         throw ex;                     }                 }             }         }

  运行效果如图2.7.1所示,生成了update语句,并已经修改了对应的记录。有的朋友就会问,为什么new的时候也能得到游离态(Detached)对象?因为判断是否为游离态(Detached)对象,是根据数据库中是否存在与之对应的记录定夺的。

图2.7.1

  代码下载

  出处:http://www.cnblogs.com/GoodHelper/archive/2011/02/17/nhibernate_04.html

  欢迎转载,但需保留版权。

NHibernate从入门到精通系列的更多相关文章

  1. NHibernate从入门到精通系列(1)——NHibernate概括

    内容摘要 NHibernate简介 ORM简介 NHibernate优缺点 一.NHibernate简介 什么是?NHibernate?NHibernate是一个面向.NET环境的对象/关系数据库映射 ...

  2. NHibernate从入门到精通系列(3)——第一个NHibernate应用程序

    内容摘要 准备工作 开发流程 程序开发 一.准备工作 1.1开发环境 开发工具:VS2008以上,我使用的是VS2010 数据库:任意关系型数据库,我使用的是SQL Server 2005 Expre ...

  3. NHibernate从入门到精通系列(2)——NHibernate环境与结构体系

    内容摘要 NHibernate的开发环境 NHibernate的结构体系 NHibernate的配置 一.NHibernate的开发环境 NHibernate的英文官方网站为:http://nhfor ...

  4. NHibernate从入门到精通系列——NHibernate环境与结构体系

    内容摘要 NHibernate的开发环境 NHibernate的结构体系 NHibernate的配置 一.NHibernate的开发环境 NHibernate的英文官方网站为:http://nhfor ...

  5. Provisioning Services 7.6 入门到精通系列之一:PVS前期规划

    1.  Provisioning Services 产品概述 Provisioning Services (简称PVS)采用了一种与传统映像解决方案截然不同的方法,从根本上改变了硬件与依托硬件而运行的 ...

  6. Jenkins pipeline 入门到精通系列文章

    Jenkins2 入门到精通系列文章. Jenkins2 下载与启动jenkins2 插件安装jenkins2 hellopipelinejenkins2 pipeline介绍jenkins2 jav ...

  7. 办公软件Office PPT 2010视频教程从入门到精通系列教程(22课时)

    办公软件Office PPT 2010视频教程从入门到精通系列教程(22课时) 乔布斯的成功离不开美轮美奂的幻灯片效果,一个成功的商务人士.部门经理也少不了各种各样的PPT幻灯片.绿色资源网给你提供了 ...

  8. Selenium 入门到精通系列:六

    Selenium 入门到精通系列 PS:Checkbox方法 例子 HTML: <html> <head> <title>测试页面</title> &l ...

  9. Selenium 入门到精通系列:五

    Selenium 入门到精通系列 PS:显式等待.隐式等待.强制等待方法 例子 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019 ...

随机推荐

  1. DNN 错误代码 0x80070005 解决方案

    在IIS上创建DNN站点,可能出现的错误代码:0x80070005,因为权限不足而不能访问DNN. 解决方法:打开IIS, 1.右键目标网站->编辑权限->安全->添加组或者用户 “ ...

  2. LeetCode(8) - String to Integer (atoi)

    虽然是easy,却是比较繁琐的一道题,需要考虑各种边界条件.在WA了好几遍之后,才把各种边界条件给补全.需要考虑到的因素如下: 输入不合法字符,非"0-9",对于首位,合法字符还包 ...

  3. dom 按着shift多选

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  4. dom div移动解决停顿问题

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  5. 使用bat快速创建cocos2d-x模板

    在上一篇文章中我们学习了如何使用python创建cocos2d-x 2.2工程,但是每次我们都输入一大串的命令,好烦好烦啊.参考别人的文章这里写了一个bat,如下 @echo off echo --- ...

  6. 解决SQLServer2008 Express远程连接出错的问题[Error: 1326错误]

    sqlserver2008 Express版本默认是只能本机测试连接,不能被其他客户端访问,原因是因为Express版本的数据库被连接默认的TCP/IP监听是被关闭的,我们可以做一些设置实现我们的远程 ...

  7. HD1085 Holding Bin-Laden Captive!

    Problem Description We all know that Bin-Laden is a notorious terrorist, and he has disappeared for ...

  8. HDU 4612 Warm up(2013多校2 1002 双连通分量)

    Warm up Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Su ...

  9. 《Pandoc用户指南》之一

    @(编程) 1. 描述 Pandoc是一个用于从一种标记格式转换为另一种的Haskell库,还是一个使用该库的命令行工具.它可以读取markdown格式和Textile格式(的子集).reStruct ...

  10. spring properties resolve 问题

    在stackoverflow上看到一个问题 配置如下: <context:property-placeholder location="/WEB-INF/application-cus ...