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. jqueryMobile

    <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8& ...

  2. BITED-Windows8应用开发学习札记之三:如何在Win8应用中实现数据绑定

    在微软官方提供的资源中,我们可以看到SampleDataSource.cs已经拥有了定义好了相应的数据结构以及实现类: 建立本地数据 由于我们已经有数据以及相应的数据类,我们需要做的仅仅是将数据放进数 ...

  3. U盘安装RedHat 5.3

    转载自http://www.cnblogs.com/totozlj/archive/2012/06/03/2532757.html 1.下载rhel-5.3-server-i386-dvd.iso文件 ...

  4. VS2012打包部署Winform程序

    打包前的准备工作: 新建一个打包部署项目,点OK,如果是第一次使用的话,会打开一个网页,按照提示的步骤来做, 点击上面的step2的网址,进入到另一个网页: 填写完右边的信息,点击“download ...

  5. ASP.NET 应用程序生命周期概述[转自MSDN]

    本文转自:http://msdn.microsoft.com/zh-cn/library/ms178473(VS.80).aspx 下表描述了 ASP.NET 应用程序生命周期的各个阶段.   阶段 ...

  6. always NetWork Performance measure Tools

    1,iperf key feature:Measuring TCP and UDP BandWidth Performance Iperf features; *TCP .Measure bandwi ...

  7. 第二百二十四天 how can I 坚持

    实物商品兑换,有点小难搞,其实也没什么难的,也就那些东西,不过好像这就是我设计实现的,干起来挺来劲的. 供暖了,挺暖和的,哈哈. 小米耳机(炫彩版)到了.感觉挺好的. 还在纠结到底要买哪种颜色的羽绒服 ...

  8. TCP包头

    每发一个包,不论大小协议头会占用一定的空间 TCP头20字节,IP头20字节,MAC头14字节,共54字节 //Mac头部,总长度14字节  typedef struct _eth_hdr  {    ...

  9. KextWizard 的使用方法;以及Kext安装的几种工具下载

    a.将你需要安装的Kext拖到非中文的路径中: b.运行该软件,将Kext拖入下图对应的方框里,然后选择位置安装: c.选择修复权限和重建缓存(一个是修复Extra文件夹,一个是修复SLE) Kext ...

  10. [iOS微博项目 - 3.1] - 发微博界面

    github: https://github.com/hellovoidworld/HVWWeibo   A.发微博界面:自定义UITextView 1.需求 用UITextView做一个编写微博的输 ...