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”配置模板
(4)引用“log4net.dll”并配置App.config,用于输出日志
<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”
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前,修改该对象的属性,最后提交事务。
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)
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方法的代码如下:
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()方法的代码如下:
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)
代码如下:
};
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)。
代码如下:
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从入门到精通系列的更多相关文章
-
NHibernate从入门到精通系列(1)——NHibernate概括
内容摘要 NHibernate简介 ORM简介 NHibernate优缺点 一.NHibernate简介 什么是?NHibernate?NHibernate是一个面向.NET环境的对象/关系数据库映射 ...
-
NHibernate从入门到精通系列(3)——第一个NHibernate应用程序
内容摘要 准备工作 开发流程 程序开发 一.准备工作 1.1开发环境 开发工具:VS2008以上,我使用的是VS2010 数据库:任意关系型数据库,我使用的是SQL Server 2005 Expre ...
-
NHibernate从入门到精通系列(2)——NHibernate环境与结构体系
内容摘要 NHibernate的开发环境 NHibernate的结构体系 NHibernate的配置 一.NHibernate的开发环境 NHibernate的英文官方网站为:http://nhfor ...
-
NHibernate从入门到精通系列——NHibernate环境与结构体系
内容摘要 NHibernate的开发环境 NHibernate的结构体系 NHibernate的配置 一.NHibernate的开发环境 NHibernate的英文官方网站为:http://nhfor ...
-
Provisioning Services 7.6 入门到精通系列之一:PVS前期规划
1. Provisioning Services 产品概述 Provisioning Services (简称PVS)采用了一种与传统映像解决方案截然不同的方法,从根本上改变了硬件与依托硬件而运行的 ...
-
Jenkins pipeline 入门到精通系列文章
Jenkins2 入门到精通系列文章. Jenkins2 下载与启动jenkins2 插件安装jenkins2 hellopipelinejenkins2 pipeline介绍jenkins2 jav ...
-
办公软件Office PPT 2010视频教程从入门到精通系列教程(22课时)
办公软件Office PPT 2010视频教程从入门到精通系列教程(22课时) 乔布斯的成功离不开美轮美奂的幻灯片效果,一个成功的商务人士.部门经理也少不了各种各样的PPT幻灯片.绿色资源网给你提供了 ...
-
Selenium 入门到精通系列:六
Selenium 入门到精通系列 PS:Checkbox方法 例子 HTML: <html> <head> <title>测试页面</title> &l ...
-
Selenium 入门到精通系列:五
Selenium 入门到精通系列 PS:显式等待.隐式等待.强制等待方法 例子 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019 ...
随机推荐
-
关于WORD文档的读取乱码问题
一直以来都是用File类操作txt文档,今天想尝试能不能打开word文档,无奈,尝试了UTF8,Unicode,Default....等编码方式,打开文件都是乱码,电脑甚至发出警报声. 以下只取一种编 ...
-
字符串去掉空格 trim()方法
jquery库提供了$.trim()方法,能直接用, 但没用库时FF里有效果,IE里就没实现, 解决办法:用正则替换 方法: function trimStr(str){return str.repl ...
-
StyleCop学习笔记——默认的规则
在StyleCop中有一些官方自己写好的检测规则下面就是英文的解释 文档规则 1.SA1600:ElementsMustBeDocumented元素必须添加注释 2.SA1601: PartialEl ...
-
ACCESS-delphi向中插入一条记录报错,但ACCESS不会
问题:在DELPHI中向ACCESS中插入一条记录时,提示“插入错误”,但是取出SQL直接放在ACCESS中插入成功?答:原因是插入语句中的字段名是DELPHI的内部标示符.
-
在LINUX中跟踪函数调用----http://*.com/
http://*.com/questions/311840/tool-to-trace-local-function-calls-in-linux I am looking f ...
-
详解AJAX核心 —— XMLHttpRequest 对象 (下)
继续上一篇的内容上一篇关于XMLHttpRequest 对象发送对服务器的请求只说到了用Get方式,没有说Post方式的.那是因为要说Post方式就需要先说另外一个东西,那就是DOM(Document ...
-
一道C语言安全编码题目
1.前言 最近在网上看到一道C语言题目,用C语言实现一个函数,给定一个int类型的整数,函数输出逆序的整数,例如输入123,则输出字符串"321",,输入-123,则输出字符串&q ...
-
jvisualvm安装visualgc插件
jdk1.7自带jvisualvm可以对java应用进行监控.其中有个插件visualgc可以查看jvm垃圾回收的具体信息.安装插件的步骤是打开jvisualvm,点击工具->插件,在可用插件列 ...
-
GMIS 2017 大会陈雨强演讲:机器学习模型,宽与深的大战
https://blog.csdn.net/starzhou/article/details/72819374 2017-05-27 19:15:36 GMIS 2017 10 0 5 ...
-
Java多层嵌套异常处理的基本流程
异常是程序中的一些错误,但并不是所有的错误都是异常,错误有时候是可以避免的.异常的对象有两个来源,一是Java运行时环境自动抛出系统生成的异常,而不管你是否愿意捕获和处理,它总要被抛出!比如除数为0的 ...