• [Nhibernate]对象状态


    目录

    写在前面

    文档与系列文章

    对象状态

    瞬时态(Transient)

    持久态(Persistent)

    脱管态(Detached)

    对象状态转换

    总结

    写在前面

    前面两篇文章介绍了SchemaExport工具的使用,使用该工具可以根据映射文件生成数据库架构,这篇文章将介绍nhibernate中的三种对象状态。

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

    瞬时对象:对象刚刚建立,该对象没有在数据库中进行存储,也没有在ISession的缓存中。如果该对象的主键是自动创建的,则此时对象的标识符为空。

    持久化对象:对象已经通过Nhibernate进行了持久化,数据库中已经存在了该对象的记录。如果该对象自动创建主键,则此时对象的标识符已被赋值。

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

    文档与系列文章

    [Nhibernate]体系结构

    [NHibernate]ISessionFactory配置

    [NHibernate]持久化类(Persistent Classes)

    [NHibernate]O/R Mapping基础

    [NHibernate]集合类(Collections)映射 

    [NHibernate]关联映射

    [NHibernate]Parent/Child

    [NHibernate]缓存(NHibernate.Caches)

    [NHibernate]NHibernate.Tool.hbm2net

    [NHibernate]Nullables

    [NHibernate]Nhibernate如何映射sqlserver中image字段

    [NHibernate]基本配置与测试 

    [NHibernate]HQL查询 

    [NHibernate]条件查询Criteria Query

    [NHibernate]增删改操作

    [NHibernate]事务

    [NHibernate]并发控制

    [NHibernate]组件之依赖对象

    [NHibernate]一对多关系(级联删除,级联添加)

    [NHibernate]一对多关系(关联查询)

    [NHibernate]多对多关系(关联查询)

    [NHibernate]延迟加载

    [NHibernate]立即加载

    [NHibernate]视图处理

    [NHibernate]N+1 Select查询问题分析

    [NHibernate]存储过程的使用(一)

    [NHibernate]存储过程的使用(二)

    [NHibernate]存储过程的使用(三)

    [Nhibernate]SchemaExport工具的使用(一)——通过映射文件修改数据表

    [Nhibernate]SchemaExport工具的使用(二)——创建表及其约束、存储过程、视图

    对象状态

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

    瞬时态(Transient)

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

    例如:刚刚创建一个Customer对象,就是一个瞬时态的对象。

     1             //瞬时态对象
     2             var customer = new Customer()
     3             {
     4                 CustomerID = Guid.NewGuid(), 
     5                 NameAddress = new Name()
     6                 { 
     7                     CustomerAddress="北京", 
     8                     CustomerName="wolfy"
     9                 }, 
    10                 Orders=null, 
    11                 Version=1 
    12             };

    持久态(Persistent)

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

    脱管态(Detached)

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

    对象状态转换

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

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

    添加一个ISession的重置方法

    1         public static ISession ResetSession()
    2         {
    3             if (_session.IsOpen)
    4                 _session.Close();
    5             _session = _sessionFactory.OpenSession(); ;
    6             return _session;
    7         }

    瞬时态转换为持久态

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

     1         public void TransientConvertPersistent()
     2         {
     3             //瞬时态对象
     4             var customer = new Customer()
     5             {
     6                 CustomerID = Guid.NewGuid(), 
     7                 NameAddress = new Name()
     8                 { 
     9                     CustomerAddress="北京", 
    10                     CustomerName="wolfy"
    11                 }, 
    12                 Orders=null, 
    13                 Version=1 
    14             };
    15             ISession session = NHibernateHelper.GetSession();
    16             if (!session.Contains(customer))
    17             {
    18                 //关联ISession保存到数据库中
    19                 session.Save(customer);
    20             }
    21             //变为持久态,由于表中CustomerId字段自动增长的(如果是自动增长主键),保存数据库,CustomerId字段自动加一
    22             //经过NHibernate类型转换后返回CustomerId属性值,保证数据库与实例对象同步
    23             if (session.Contains(customer))
    24             {
    25 
    26             }
    27         }

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

    持久态转换为脱管态

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

     1         public void PersistentConvertDetachedEvict()
     2         {
     3             //得到session
     4             ISession session = NHibernateHelper.GetSession();
     5             //根据id得到customer对象
     6             var customer = session.Get("Customer", new Guid("DDF63750-3307-461B-B96A-7FF356540CB8"));
     7             //如果包含customer对象则删除
     8             if (session.Contains(customer))
     9             {
    10                 session.Evict(customer);
    11             }
    12         }

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

     1        public void PersistentConvertDetachedCloseTest()
     2         {
     3             //得到session
     4             ISession session = NHibernateHelper.GetSession();
     5             //根据id得到customer对象
     6             var customer = session.Get("Customer", new Guid("DDF63750-3307-461B-B96A-7FF356540CB8"));
     7             if (session.Contains(customer))
     8             {
     9                 NHibernateHelper.ResetSession();
    10             }
    11         }

    脱管态转换为持久态

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

     1         public void DetachedConvertPersistentUpdateTest()
     2         {
     3             //得到session
     4             ISession session = NHibernateHelper.GetSession();
     5             //根据id得到customer对象
     6             Customer customer = session.Get("Customer", new Guid("DDF63750-3307-461B-B96A-7FF356540CB8")) as Customer;
     7             //重新设置ISession
     8             NHibernateHelper.ResetSession();
     9             //脱管态对象
    10             //在脱管态下可继续被修改
    11             if (session.Contains(customer))
    12             {
    13                 customer.NameAddress = new Name() { CustomerAddress="上海", CustomerName="wolfy"};
    14                 //转变为持久态对象
    15                 session.Update(customer);
    16             }           
    17         }

    通过上面的例子可以看出:在托管时期的修改会被持久化到数据库中;

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

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

     1         public void DetachedConvertPersistentUpdateLockTest()
     2         {
     3             //得到session
     4             ISession session = NHibernateHelper.GetSession();
     5             //根据id得到customer对象
     6             Customer customer = session.Get("Customer", new Guid("DDF63750-3307-461B-B96A-7FF356540CB8")) as Customer;
     7             if (session.Contains(customer))
     8             {
     9                 NHibernateHelper.ResetSession();
    10             }
    11             //
    12             session.Lock(customer, NHibernate.LockMode.None);
    13             //如果在托管时期没有修改,就不执行更新语句,只转换为持久态
    14             session.Update(customer);
    15         }

    需注意Lock锁的使用,需要保证customer对象不为null,这里为了测试方便就没加上判断。如果为null会有异常(attempt to lock null)。

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

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

    总结

    本篇概念性的东西比较多,对三种状态的理解到位,就能区别三种状态。

    参考文章

    http://www.cnblogs.com/lyj/archive/2008/11/17/1335181.html

  • 相关阅读:
    python基础学习-day13==课后作业练习(函数的基本使用)
    python基础学习-函数的基本使用
    python基础学习-day12==课后作业练习(文件指针的控制操作)
    python基础学习-文件其他操作模式(补充)
    python基础学习-day11==课后作业练习(文件操作)
    python基础学习-文件处理
    简单页面设计
    前端.浮动.定位框
    css属性and盒模型
    用html搭建一个注册页面
  • 原文地址:https://www.cnblogs.com/wolf-sun/p/4124960.html
Copyright © 2020-2023  润新知