NHibernate从入门到精通系列

时间:2022-09-02 00:17:46

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

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

 

  

  内容摘要

    持久对象的状态的概念

    持久对象的状态Demo

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

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

NHibernate从入门到精通系列

图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所示,准备完成后,便可以开始我们的演示。

NHibernate从入门到精通系列

图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语句。

NHibernate从入门到精通系列

图2.2.1

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

NHibernate从入门到精通系列

图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)。

NHibernate从入门到精通系列

图2.3.1

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

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

NHibernate从入门到精通系列

图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语句。

NHibernate从入门到精通系列

图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”提供的。

NHibernate从入门到精通系列

图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语句。

NHibernate从入门到精通系列

图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)对象,是根据数据库中是否存在与之对应的记录定夺的。

NHibernate从入门到精通系列

图2.7.1

  代码下载

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

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

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

  1. NHibernate从入门到精通系列&lpar;1&rpar;——NHibernate概括

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

  2. NHibernate从入门到精通系列&lpar;3&rpar;——第一个NHibernate应用程序

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

  3. NHibernate从入门到精通系列&lpar;2&rpar;——NHibernate环境与结构体系

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

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

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

  5. Provisioning Services 7&period;6 入门到精通系列之一:PVS前期规划

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

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

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

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

    办公软件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. 关于WORD文档的读取乱码问题

    一直以来都是用File类操作txt文档,今天想尝试能不能打开word文档,无奈,尝试了UTF8,Unicode,Default....等编码方式,打开文件都是乱码,电脑甚至发出警报声. 以下只取一种编 ...

  2. 字符串去掉空格 trim&lpar;&rpar;方法

    jquery库提供了$.trim()方法,能直接用, 但没用库时FF里有效果,IE里就没实现, 解决办法:用正则替换 方法: function trimStr(str){return str.repl ...

  3. StyleCop学习笔记——默认的规则

    在StyleCop中有一些官方自己写好的检测规则下面就是英文的解释 文档规则 1.SA1600:ElementsMustBeDocumented元素必须添加注释 2.SA1601: PartialEl ...

  4. ACCESS-delphi向中插入一条记录报错,但ACCESS不会

    问题:在DELPHI中向ACCESS中插入一条记录时,提示“插入错误”,但是取出SQL直接放在ACCESS中插入成功?答:原因是插入语句中的字段名是DELPHI的内部标示符.

  5. 在LINUX中跟踪函数调用----http&colon;&sol;&sol;*&period;com&sol;

    http://*.com/questions/311840/tool-to-trace-local-function-calls-in-linux I am looking f ...

  6. 详解AJAX核心 —— XMLHttpRequest 对象 &lpar;下&rpar;

    继续上一篇的内容上一篇关于XMLHttpRequest 对象发送对服务器的请求只说到了用Get方式,没有说Post方式的.那是因为要说Post方式就需要先说另外一个东西,那就是DOM(Document ...

  7. 一道C语言安全编码题目

    1.前言 最近在网上看到一道C语言题目,用C语言实现一个函数,给定一个int类型的整数,函数输出逆序的整数,例如输入123,则输出字符串"321",,输入-123,则输出字符串&q ...

  8. jvisualvm安装visualgc插件

    jdk1.7自带jvisualvm可以对java应用进行监控.其中有个插件visualgc可以查看jvm垃圾回收的具体信息.安装插件的步骤是打开jvisualvm,点击工具->插件,在可用插件列 ...

  9. GMIS 2017 大会陈雨强演讲:机器学习模型,宽与深的大战

    https://blog.csdn.net/starzhou/article/details/72819374 2017-05-27 19:15:36     GMIS 2017    10 0 5 ...

  10. Java多层嵌套异常处理的基本流程

    异常是程序中的一些错误,但并不是所有的错误都是异常,错误有时候是可以避免的.异常的对象有两个来源,一是Java运行时环境自动抛出系统生成的异常,而不管你是否愿意捕获和处理,它总要被抛出!比如除数为0的 ...