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

本节内容

  • 引入
  • 对象状态
  • 对象状态转换
  • 结语

引入

在程序运行过程中使用对象的方式对数据库进行操作,这必然会产生一系列的持久化类的实例对象。这些对象可能是刚刚创建并准备存储的,也可能是从数据库中查询的,为了区分这些对象,根据对象和当前会话的关联状态,我们可以把对象分为三种:

瞬时对象:对象刚刚建立。该对象在数据库中没有记录,也不在ISession缓存中。如果该对象是自动生成主键,则该对象的对象标识符为空。

持久化对象:对象已经通过NHibernate进行了持久化,数据库中已经存在对应的记录。如果该对象是自动生成主键,则该对象的对象标识符已被赋值。

托管对象:该对象是经过NHibernate保存过或者从数据库中取出的,但是与之关联的ISession已经关闭。虽然它有对象标识符且数据库中存在对应记录,但是已经不再被NHibernate管理。

对象状态

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

1.瞬时态(Transient)

对象刚刚创建,还没有来及和ISession关联的状态。这时瞬时对象不会被持久化到数据库中,也不会被赋上标识符。如果不使用则被GC销毁。ISession接口可以将其转换为持久状态。

这像这样,刚刚创建了一个Customer对象,是一个瞬时态对象:

var customer = new Customer() { Firstname = "YJing", Lastname = "Lee"  };

2.持久态(Persistent)

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

3.托管态(Detached)

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

对象状态转换

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

测试验证对象

ISession.Contains(object):检查ISession中是否包含指定实例

重新设置ISession

private void ResetSession()
{
    if (_session.IsOpen)
        _session.Close();
    _session = _sessionManager.GetSession();
    _transaction.Session = _session;
}

1.瞬时态转换持久态

方法一:ISession.Save():保存指定实例。

[Test]
public void TransientConvertPersistentTest()
{
    //瞬时态对象
    var customer = new Customer() { Firstname = "YJidng", Lastname = "Lee" };
    Assert.IsFalse(_session.Contains(customer));
    //仍然是瞬时态,CustomerId属性值为空

    //关联ISession保存到数据库中
    _session.Save(customer);
    //变为持久态,由于表中CustomerId字段自动增长的,保存数据库,CustomerId字段自动加一
    //经过NHibernate类型转换后返回CustomerId属性值,保证数据库与实例对象同步
    Assert.IsTrue(_session.Contains(customer));
}

方法二:ISession.SaveOrUpdate():分配新标识保存瞬时态对象。

2.持久态转换托管态

方法一:ISession.Evict(object):从当前ISession中删除指定实例

[Test]
public void PersistentConvertDetachedEvictTest()
{
    Customer customer = _transaction.GetCustomerById(1);
    Assert.IsTrue(_session.Contains(customer));
    _session.Evict(customer);
    Assert.IsFalse(_session.Contains(customer));
}

方法二:ISession.Close():关闭当前ISession

[Test]
public void PersistentConvertDetachedCloseTest()
{
    Customer customer = _transaction.GetCustomerById(1);
    Assert.IsTrue(_session.Contains(customer));
    ResetSession();
    Assert.IsFalse(_session.Contains(customer));
}

3.托管态转换持久态

方法一:ISession.Update():更新指定实例。

[Test]
public void DetachedConvertPersistentUpdateTest()
{
    Customer customer = _transaction.GetCustomerById(1);
    //持久态对象
    Assert.IsTrue(_session.Contains(customer));
    //重新设置ISession
    ResetSession();
    Assert.IsFalse(_session.Contains(customer));
    //托管态对象
    //在托管态下可继续被修改
    customer.Firstname += "CnBlogs";
    _transaction.UpdateCustomerTransaction(customer);
    //转变为持久态对象
    Assert.IsTrue(_session.Contains(customer));
}

看看这个例子:在托管时期的修改会被持久化到数据库中;

注意:NHibernate如何知道重新关联的对象是不是“脏的(修改过的)”?如果是新的ISession,ISession就不能与对象初值来比较这个对象是不是“脏的”,我们在映射文件中定义<id>元素和<version>元素的unsaved-value属性,NHibernate就可以自己判断了。

[Test]
public void DetachedConvertPersistentUpdateAllTest()
{
    Customer customer = _transaction.GetCustomerById(1);
    //持久态对象
    customer.Firstname += "YJingLee";
    Assert.IsTrue(_session.Contains(customer));
    //重新设置ISession
    ResetSession();
    Assert.IsFalse(_session.Contains(customer));
    //托管态对象
    //在托管态下可继续被修改
    customer.Firstname += "CnBlogs";
    //这时一起更新
    _transaction.UpdateCustomerTransaction(customer);
    //转变为持久态对象
    Assert.IsTrue(_session.Contains(customer));
}

这个加上一个锁:如果在托管时期没有修改,就不执行更新语句,只转换为持久态,下面的例子如果在托管时期修改对象,执行更新语句。

[Test]
public void DetachedConvertPersistentUpdateLockTest()
{
    Customer customer = _transaction.GetCustomerById(1);
    Assert.IsTrue(_session.Contains(customer));
    ResetSession();
    Assert.IsFalse(_session.Contains(customer));
    //锁
    _session.Lock(customer, NHibernate.LockMode.None);
    //如果在托管时期没有修改,就不执行更新语句,只转换为持久态
    //customer.Firstname += "CnBlogs";
    _transaction.UpdateCustomerTransaction(customer);
    Assert.IsTrue(_session.Contains(customer));
}

方法二:ISession.Merge():合并指定实例。不必考虑ISession状态,ISession中存在相同标识的持久化对象时,NHibernate便会根据用户给出的对象状态覆盖原有的持久化实例状态。

方法三:ISession.SaveOrUpdate():分配新标识保存瞬时态对象;更新/重新关联托管态对象。

以上两个大家自己测试了!

结语

这篇初步知道了对象的状态。虽然对象的状态的细节由NHibernate自己维护,但是对象状态在NHibernate应用中还是比较重要的。同时对象状态也涉及了NHibernate缓存、离线查询等内容。

时间: 2024-11-07 01:57:46

NHibernate之旅(21):探索对象状态的相关文章

NHibernate之旅系列文章导航

NHibernate之旅系列文章导航 宣传语 NHibernate.NHibernate教程.NHibernate入门.NHibernate下载.NHibernate教程中文版.NHibernate实例.NHibernate2.0.NHibernate2.0教程.NHibernate之旅.NHibernate工具 我的NHibernate全部文章在http://www.cnblogs.com/lyj/category/129155.html 导游 NHibernate是把Java的Hiberna

NHibernate之旅(17):探索NHibernate中使用存储过程(下)

本节内容 引入 实例分析 拾遗 结语 引入 上两篇,介绍使用MyGeneration提供的模板创建存储过程和删除对象.创建对象.更新对象整个详细过程,这篇介绍如何利用<sql-query>做更多的事,在程序开发中,我们不仅仅只利用存储过程增删查改对象,我们还可以想执行任意的存储过程,这不局限于某个对象,某个CURD操作,怎么做呢?注意:本篇并非官方权威的资料,所以敬请参考.如果你还没有学习NHibernate,请快速链接到NHibernate之旅系列文章导航. 实例分析 下面我用几个例子来分析

NHibernate之旅(4):探索查询之条件查询(Criteria Query)

本节内容 NHibernate中的查询方法 条件查询(Criteria Query) 1.创建ICriteria实例 2.结果集限制 3.结果集排序 4.一些说明 根据示例查询(Query By Example) 实例分析 结语 上一节,我们介绍了NHibernate查询语言的一种:NHibernate查询语言(HQL,NHibernate Query Language),这一节介绍一下条件查询(Criteria API). NHibernate中的查询方法 在NHibernate中提供了三种查

NHibernate之旅(11):探索多对多关系及其关联查询

本节内容 多对多关系引入 多对多映射关系 多对多关联查询 1.原生SQL关联查询 2.HQL关联查询 3.Criteria API关联查询 结语 多对多关系引入 让我们再次回顾在第二篇中建立的数据模型: 在图上,我已经清晰的标注了表之间的关系,上两篇分析Customer和Order之间的"外键关系"或者称作"父子关系"."一对多关系"和关联查询,这一篇以Order为中心,分析Order和Product之间的关系,直接看下面一幅图的两张表: 上面两

[转]NHibernate之旅(11):探索多对多关系及其关联查询

本节内容 多对多关系引入 多对多映射关系 多对多关联查询 1.原生SQL关联查询 2.HQL关联查询 3.Criteria API关联查询 结语 多对多关系引入 让我们再次回顾在第二篇中建立的数据模型: 在图上,我已经清晰的标注了表之间的关系,上两篇分析Customer和Order之间的“外键关系”或者称作“父子关系”.“一对多关系”和关联查询,这一篇以Order为中心,分析Order和Product之间的关系,直接看下面一幅图的两张表: 上面两张表关系表达的意思是:Order有多个Produc

NHibernate之旅(18):初探代码生成工具使用

本节内容 引入 代码生成工具 结语 引入 我们花了大量的篇幅介绍了相关NHibernate的知识.一直都是带着大家手动编写代码,首先创建数据库架构.然后编写持久化类和映射文件,最后编写数据操作方法.測试方法. 这是典型的数据库驱动开发(DbDD,Database-Driven Developent)技术.可是自己不是这样做的,我先编写持久化类和映射文件,然后偷偷的使用SchemaExport工具把数据库生成了.按上面的步骤写文章的,关于SchemaExport工具就是下一篇的事情了,这篇说说利用

hibernate学习(5)——对象状态与一级缓存

1.对象状态 1.1   状态介绍 hibernate 规定三种状态:瞬时态.持久态.脱管态 瞬时态:transient,session没有缓存对象,数据库也没有对应记录.没有与hibernate关联,与数据库中的记录没有产生关联. OID特点:没有值 持久态:persistent,session缓存对象,数据库最终会有记录.(事务没有提交)与hibernate关联,对象有id OID特点:有值 脱管态:detached,session没有缓存对象,数据库有记录.没有与hibernate关联,对

探索对象池技术

对象池技术是一种常见的对象缓存手段.’对象’意味着池中的内容是一种结构化实体,这也就是一般意义上面向对象中的对象模型:’池’(或动词池化)意味着将有生命周期的对象缓存到’池子’中进行管理,即用即取.缓存的目的大多是为了提升性能,对象池技术的目的也即如此.所以,对象池技术的本质简单来说就是:将具有生命周期的结构化对象缓存到带有一定管理功能的容器中,以提高对象的访问性能. 处理网络连接是对象池使用最多的场景.比如一些RPC框架的NettyChannel缓存(如motan),以及数据库连接池的Conn

使用序列化保存对象状态到存储介质

//使用序列化保存对象状态到存储介质 //添加[Serializable] Game game = new Game(); game.Level = 2; game.Player = "Tom"; FileStream fs = new FileStream(@"game.bin",FileMode.Create); BinaryFormatter bf = new BinaryFormatter(); bf.Serialize(fs,game); //使用反序列化