找回密码
 立即注册
首页 业界区 业界 NHibernate之旅(21):探索对象状态

NHibernate之旅(21):探索对象状态

忿惺噱 2025-5-30 01:26:32
本节内容
           
  • 引入       
  • 对象状态       
  • 对象状态转换       
  • 结语
引入

在程序运行过程中使用对象的方式对数据库进行操作,这必然会产生一系列的持久化类的实例对象。这些对象可能是刚刚创建并准备存储的,也可能是从数据库中查询的,为了区分这些对象,根据对象和当前会话的关联状态,我们可以把对象分为三种:
瞬时对象:对象刚刚建立。该对象在数据库中没有记录,也不在ISession缓存中。如果该对象是自动生成主键,则该对象的对象标识符为空。
持久化对象:对象已经通过NHibernate进行了持久化,数据库中已经存在对应的记录。如果该对象是自动生成主键,则该对象的对象标识符已被赋值。
托管对象:该对象是经过NHibernate保存过或者从数据库中取出的,但是与之关联的ISession已经关闭。虽然它有对象标识符且数据库中存在对应记录,但是已经不再被NHibernate管理。
对象状态

NHibernate提供了对象状态管理的功能,支持三种对象状态:瞬时态(Transient)、持久态(Persistent)、托管态(Detached)。
1.瞬时态(Transient)

对象刚刚创建,还没有来及和ISession关联的状态。这时瞬时对象不会被持久化到数据库中,也不会被赋上标识符。如果不使用则被GC销毁。ISession接口可以将其转换为持久状态。
这像这样,刚刚创建了一个Customer对象,是一个瞬时态对象:
  1. var customer = new Customer() { Firstname = "YJing", Lastname = "Lee"  };
复制代码
2.持久态(Persistent)

刚被保存的或刚从数据库中加载的。对象仅在相关联的ISession生命周期内有效,在数据库中有相应记录并有标识符。对象实例由NHibernate框架管理,如果有任何改动,在当然操作提交时,与数据库同步,即将对象保存更新到数据库中。
3.托管态(Detached)

持久对象关联的ISession关闭后,这个对象在ISession中脱离了关系,就是托管态了,托管对象仍然有持久对象的所有属性,对托管对象的引用仍然有效的,我们可以继续修改它。如果把这个对象重新关联到ISession上,则再次转变为持久态,在托管时期的修改会被持久化到数据库中。
对象状态转换

在同步数据库的情况下执行下面的语句可以转换对象的状态。
测试验证对象

ISession.Contains(object):检查ISession中是否包含指定实例
重新设置ISession
  1. private void ResetSession()
  2. {
  3.     if (_session.IsOpen)
  4.         _session.Close();
  5.     _session = _sessionManager.GetSession();
  6.     _transaction.Session = _session;
  7. }
复制代码
1.瞬时态转换持久态

方法一:ISession.Save():保存指定实例。
  1. [Test]
  2. public void TransientConvertPersistentTest()
  3. {
  4.     //瞬时态对象
  5.     var customer = new Customer() { Firstname = "YJidng", Lastname = "Lee" };
  6.     Assert.IsFalse(_session.Contains(customer));
  7.     //仍然是瞬时态,CustomerId属性值为空
  8.     //关联ISession保存到数据库中
  9.     _session.Save(customer);
  10.     //变为持久态,由于表中CustomerId字段自动增长的,保存数据库,CustomerId字段自动加一
  11.     //经过NHibernate类型转换后返回CustomerId属性值,保证数据库与实例对象同步
  12.     Assert.IsTrue(_session.Contains(customer));
  13. }
复制代码
方法二:ISession.SaveOrUpdate():分配新标识保存瞬时态对象。
2.持久态转换托管态

方法一:ISession.Evict(object):从当前ISession中删除指定实例
  1. [Test]
  2. public void PersistentConvertDetachedEvictTest()
  3. {
  4.     Customer customer = _transaction.GetCustomerById(1);
  5.     Assert.IsTrue(_session.Contains(customer));
  6.     _session.Evict(customer);
  7.     Assert.IsFalse(_session.Contains(customer));
  8. }
复制代码
方法二:ISession.Close():关闭当前ISession
  1. [Test]
  2. public void PersistentConvertDetachedCloseTest()
  3. {
  4.     Customer customer = _transaction.GetCustomerById(1);
  5.     Assert.IsTrue(_session.Contains(customer));
  6.     ResetSession();
  7.     Assert.IsFalse(_session.Contains(customer));
  8. }
复制代码
3.托管态转换持久态

方法一:ISession.Update():更新指定实例。
  1. [Test]
  2. public void DetachedConvertPersistentUpdateTest()
  3. {
  4.     Customer customer = _transaction.GetCustomerById(1);
  5.     //持久态对象
  6.     Assert.IsTrue(_session.Contains(customer));
  7.     //重新设置ISession
  8.     ResetSession();
  9.     Assert.IsFalse(_session.Contains(customer));
  10.     //托管态对象
  11.     //在托管态下可继续被修改
  12.     customer.Firstname += "CnBlogs";
  13.     _transaction.UpdateCustomerTransaction(customer);
  14.     //转变为持久态对象
  15.     Assert.IsTrue(_session.Contains(customer));
  16. }
复制代码
看看这个例子:在托管时期的修改会被持久化到数据库中;
注意:NHibernate如何知道重新关联的对象是不是“脏的(修改过的)”?如果是新的ISession,ISession就不能与对象初值来比较这个对象是不是“脏的”,我们在映射文件中定义元素和元素的unsaved-value属性,NHibernate就可以自己判断了。
  1. [Test]
  2. public void DetachedConvertPersistentUpdateAllTest()
  3. {
  4.     Customer customer = _transaction.GetCustomerById(1);
  5.     //持久态对象
  6.     customer.Firstname += "YJingLee";
  7.     Assert.IsTrue(_session.Contains(customer));
  8.     //重新设置ISession
  9.     ResetSession();
  10.     Assert.IsFalse(_session.Contains(customer));
  11.     //托管态对象
  12.     //在托管态下可继续被修改
  13.     customer.Firstname += "CnBlogs";
  14.     //这时一起更新
  15.     _transaction.UpdateCustomerTransaction(customer);
  16.     //转变为持久态对象
  17.     Assert.IsTrue(_session.Contains(customer));
  18. }
复制代码
这个加上一个锁:如果在托管时期没有修改,就不执行更新语句,只转换为持久态,下面的例子如果在托管时期修改对象,执行更新语句。
  1. [Test]
  2. public void DetachedConvertPersistentUpdateLockTest()
  3. {
  4.     Customer customer = _transaction.GetCustomerById(1);
  5.     Assert.IsTrue(_session.Contains(customer));
  6.     ResetSession();
  7.     Assert.IsFalse(_session.Contains(customer));
  8.     //锁
  9.     _session.Lock(customer, NHibernate.LockMode.None);
  10.     //如果在托管时期没有修改,就不执行更新语句,只转换为持久态
  11.     //customer.Firstname += "CnBlogs";
  12.     _transaction.UpdateCustomerTransaction(customer);
  13.     Assert.IsTrue(_session.Contains(customer));
  14. }
复制代码
方法二:ISession.Merge():合并指定实例。不必考虑ISession状态,ISession中存在相同标识的持久化对象时,NHibernate便会根据用户给出的对象状态覆盖原有的持久化实例状态。
方法三:ISession.SaveOrUpdate():分配新标识保存瞬时态对象;更新/重新关联托管态对象。
以上两个大家自己测试了!
结语

这篇初步知道了对象的状态。虽然对象的状态的细节由NHibernate自己维护,但是对象状态在NHibernate应用中还是比较重要的。同时对象状态也涉及了NHibernate缓存、离线查询等内容。
本系列链接:NHibernate之旅系列文章导航
NHibernate Q&A
           
  • 欢迎加入NHibernate中文社区,一起讨论NHibernate知识!       
  • 请到NHibernate中文社区下载本系列相关源码。
下次继续分享NHibernate!

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册