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
欢迎转载,但需保留版权。