NHibernate从入门到精通系列

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

 

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

 

  

  内容摘要数据库

    持久对象的状态的概念缓存

    持久对象的状态Demosession

 

  1、持久对象的状态的概念  app

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

图1.1post

  • 临时态(Transient):用new建立的对象,它没有持久化,没有归入Session中,随时能够被垃圾回收,处于此状态的对象叫临时对象。特色:数据库中没有与之对应的记录;
  • 持久态(Persistent):已经持久化,加入到了Session缓存中。经过NHibernate保存的对象或经过Get/Load等方法获取出的对象,其对象没有脱离Session的管理,处于此状态的对象叫持久对象;
  • 游离态(Detached):持久化对象脱离了Session的对象。如Session缓存被清空的对象。特色:已经持久化,但不在Session缓存中。处于此状态的对象叫游离对象;

 

  2、持久对象的状态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

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

相关文章
相关标签/搜索