在 NHibernate中有三种状态。
- 临时态(Transient):用new创建的对象,它没有持久化,没有纳入Session中,随时可以被垃圾回收,处于此状态的对象叫临时对象。特点:数据库中没有与之对应的记录;
- 持久态(Persistent):已经持久化,加入到了Session缓存中。通过NHibernate保存的对象或通过Get/Load等方法获取出的对象,其对象没有脱离Session的管理,处于此状态的对象叫持久对象;
- 游离态(Detached):持久化对象脱离了Session的对象。如Session缓存被清空的对象。特点:已经持久化,但不在Session缓存中。处于此状态的对象叫游离对象;
临时态(Transient)到持久态(Persistent)
先new一个对象,该对象的状态为Transient,然后调用Save()方法将该对象持久化到数据库中,该对象的状态变为Persistent。在未关闭Session前,修改该对象的属性,最后提交事务。
1 /// <summary> 2 /// 临时态-->持久态 3 /// </summary> 4 [Test] 5 public void TransientToPersistentTest() 6 { 7 using (ISession session = this.sessionFactory.OpenSession()) 8 { 9 using (ITransaction tran = session.BeginTransaction()) 10 { 11 //Transient 12 var product = new Product 13 { 14 ID = Guid.NewGuid(), 15 BuyPrice = 10M, 16 Code = "ABC123", 17 Name = "电脑", 18 QuantityPerUnit = "20x1", 19 SellPrice = 11M, 20 Unit = "台" 21 22 }; 23 24 try 25 { 26 //Persistent 27 session.Save(product); 28 29 //保存记录后修改数据,观察数据库中数据的变化 30 product.SellPrice = 12M; 31 32 tran.Commit(); 33 } 34 catch (Exception ex) 35 { 36 tran.Rollback(); 37 throw ex; 38 } 39 } 40 } 41 }
这时,我们心里便产生了一个疑问:把Product的SellPrice属性从“11M”修改为“12M”后,并没有调用Save()或者Update()的方法,为什么数据库中的数据会变呢?
这是因为,当对象处于Persistent状态,并没有脱离Session管理时,其属性发生改变后,数据库相对应的记录会与之同步。
持久态(Persistent)到游离态(Detached),再到持久态(Persistent)
1 /// <summary> 2 /// 持久态-->游离态-->持久态 3 /// </summary> 4 [Test] 5 public void PersistentToTestDetached() 6 { 7 //Transient 8 var product = new Product 9 { 10 ID = Guid.NewGuid(), 11 BuyPrice = 10M, 12 Code = "ABC123", 13 Name = "电脑", 14 QuantityPerUnit = "20x1", 15 SellPrice = 11M, 16 Unit = "台" 17 }; 18 19 using (ISession session = this.sessionFactory.OpenSession()) 20 { 21 using (ITransaction tran = session.BeginTransaction()) 22 { 23 try 24 { 25 //Persistent 26 session.Save(product); 27 product.SellPrice = 12M; 28 29 tran.Commit(); 30 } 31 catch (Exception ex) 32 { 33 tran.Rollback(); 34 throw ex; 35 } 36 } 37 } 38 39 //Detached 40 product.SellPrice = 13M; 41 42 using (ISession session = this.sessionFactory.OpenSession()) 43 { 44 using (ITransaction tran = session.BeginTransaction()) 45 { 46 try 47 { 48 //Persistent 49 session.Update(product); 50 tran.Commit(); 51 } 52 catch (Exception ex) 53 { 54 tran.Rollback(); 55 throw ex; 56 } 57 } 58 } 59 }
当对象处于游离态(Detached)时,修改其属性,是不会与数据库发生同步的。调用Update()方法后,对象则变回持久态(Persistent)。
Get方法得到持久态(Persistent)
1 [Test] 2 public void PersistentToTestDetached() 3 { 4 //Transient 5 string ID1 = Guid.NewGuid().ToString(); 6 var product = new Product 7 { 8 ID = ID1, 9 BuyPrice = 10M, 10 Code = "ABC123", 11 Name = "电脑", 12 QuantityPerUnit = "20x1", 13 SellPrice = 11M, 14 Unit = "台" 15 }; 16 17 using (ISession session = this.sessionFactory.OpenSession()) 18 { 19 using (ITransaction tran = session.BeginTransaction()) 20 { 21 try 22 { 23 //Persistent 24 session.Save(product); 25 product.SellPrice = 12M; 26 27 tran.Commit(); 28 } 29 catch (Exception ex) 30 { 31 tran.Rollback(); 32 throw ex; 33 } 34 } 35 } 36 37 //Detached 38 39 40 using (ISession session = this.sessionFactory.OpenSession()) 41 { 42 using (ITransaction tran = session.BeginTransaction()) 43 { 44 try 45 { 46 //Persistent 47 product=session.Get<Product>(ID1);//Get可与Load互换 48 product.SellPrice = 18M; 49 tran.Commit(); 50 } 51 catch (Exception ex) 52 { 53 tran.Rollback(); 54 throw ex; 55 } 56 } 57 } 58 }
其中ID1为数据库中已存在的一条数据的主键值。在得到持久化对象后,我们便可以更改数据库的值。
Get和Load()方法的区别
Load:
- Load方法可以对查询进行优化。
- Load方法实际得到一proxy对象,并不立即查询数据库。当访问对象的属性的时候才查询数据库。在NHibernate里称为Lazy Loding(延迟加载)。
- Load方法得到的对象,如果对象不存在,在访问对象的属性时将抛出异常。
- 当需要得到实体对象,但是不需要访问对象属性的时候,宜使用Load方法。比如Delete方法:
调用Load()方法查询数据库中不存在的对象,返回值不为空;当调用Load()方法时,不立刻产生SQL语句,查看其属性后才产生SQL语句,并且查看数据库中不存在对象的属性时会抛出异常。原因是调用Load()方法会返回一个“代理类”,这是NHibernate的一个重要的特性——延迟加载。
延迟加载(lazy load)也叫“懒加载”,是NHibernate关联关系对象默认的加载方式,延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。可以简单理解为,只有在使用的时候,才会发出SQL语句进行查询。 延迟加载的有效期是在Session打开的情况下,当Session关闭后,会报异常。NHibernate的代理对象是由第三方组件“Antlr3.Runtime”提供的。
Get:
- Get方法立即查询数据库,如果对象不存在,返回null。
- 调用Get()方法后,数据库中不存在的对象返回值为null,并且一但调用Get()方法,就会生成SQL语句。
Update()方法
先手动打造new一个数据库中存在的游离态(Detached)对象,然后直接调用Update()方法将对象的状态设置为持久态(Persistent)。
1 [Test] 2 public void UpdateTest() 3 { 4 Guid id = Guid.NewGuid(); 5 6 using (ISession session = this.sessionFactory.OpenSession()) 7 { 8 using (ITransaction tran = session.BeginTransaction()) 9 { 10 //Transient 11 var product = new Product 12 { 13 ID = id, 14 BuyPrice = 10M, 15 Code = "ABC123", 16 Name = "电脑", 17 QuantityPerUnit = "20x1", 18 SellPrice = 11M, 19 Unit = "台" 20 21 }; 22 23 try 24 { 25 //Persistent 26 session.Save(product); 27 tran.Commit(); 28 } 29 catch (Exception ex) 30 { 31 tran.Rollback(); 32 throw ex; 33 } 34 } 35 } 36 37 using (ISession session = this.sessionFactory.OpenSession()) 38 { 39 using (ITransaction tran = session.BeginTransaction()) 40 { 41 //Detached 42 var product = new Product 43 { 44 ID = id, 45 Code = "ABC456", 46 }; 47 48 try 49 { 50 //Persistent 51 session.Update(product); 52 53 tran.Commit(); 54 } 55 catch (Exception ex) 56 { 57 tran.Rollback(); 58 throw ex; 59 } 60 } 61 } 62 }
有的朋友就会问,为什么new的时候也能得到游离态(Detached)对象?因为判断是否为游离态(Detached)对象,是根据数据库中是否存在与之对应的记录定夺的。
Delete()方法
先得到一个持久态(Persistent)对象,然后调用Delete()方法删除该对象,这时该对象变回临时态(Transient)
1 [Test] 2 public void DeleteTest() 3 { 4 using (ISession session = this.sessionFactory.OpenSession()) 5 { 6 using (ITransaction tran = session.BeginTransaction()) 7 { 8 //Transient 9 var product = new Product 10 { 11 ID = Guid.NewGuid(), 12 BuyPrice = 10M, 13 Code = "ABC123", 14 Name = "电脑", 15 QuantityPerUnit = "20x1", 16 SellPrice = 11M, 17 Unit = "台" 18 19 }; 20 21 try 22 { 23 //Persistent 24 session.Save(product); 25 26 //Transient 27 session.Delete(product); 28 29 tran.Commit(); 30 } 31 catch (Exception ex) 32 { 33 tran.Rollback(); 34 throw ex; 35 } 36 } 37 } 38 }
学习于 http://www.cnblogs.com/GoodHelper/archive/2011/02/17/nhibernate_04.html