NHibernate从入门到精通系列
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 ...
随机推荐
- DNN 错误代码 0x80070005 解决方案
在IIS上创建DNN站点,可能出现的错误代码:0x80070005,因为权限不足而不能访问DNN. 解决方法:打开IIS, 1.右键目标网站->编辑权限->安全->添加组或者用户 “ ...
- LeetCode(8) - String to Integer (atoi)
虽然是easy,却是比较繁琐的一道题,需要考虑各种边界条件.在WA了好几遍之后,才把各种边界条件给补全.需要考虑到的因素如下: 输入不合法字符,非"0-9",对于首位,合法字符还包 ...
- dom 按着shift多选
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- dom div移动解决停顿问题
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- 使用bat快速创建cocos2d-x模板
在上一篇文章中我们学习了如何使用python创建cocos2d-x 2.2工程,但是每次我们都输入一大串的命令,好烦好烦啊.参考别人的文章这里写了一个bat,如下 @echo off echo --- ...
- 解决SQLServer2008 Express远程连接出错的问题[Error: 1326错误]
sqlserver2008 Express版本默认是只能本机测试连接,不能被其他客户端访问,原因是因为Express版本的数据库被连接默认的TCP/IP监听是被关闭的,我们可以做一些设置实现我们的远程 ...
- HD1085 Holding Bin-Laden Captive!
Problem Description We all know that Bin-Laden is a notorious terrorist, and he has disappeared for ...
- 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 ...
- 《Pandoc用户指南》之一
@(编程) 1. 描述 Pandoc是一个用于从一种标记格式转换为另一种的Haskell库,还是一个使用该库的命令行工具.它可以读取markdown格式和Textile格式(的子集).reStruct ...
- spring properties resolve 问题
在stackoverflow上看到一个问题 配置如下: <context:property-placeholder location="/WEB-INF/application-cus ...