如何在休眠中识别对象是暂时的还是分离的?

时间:2013-10-20 06:00:43

标签: hibernate

我知道瞬态实例意味着实例是新创建的,并且数据库中不存在相应的行,因为分离的实例在数据库中具有相应的条目,但目前没有与任何会话相关联。

有没有什么方法可以使用Session上的任何方法或者以编程方式在hibernate中使用其他方法来识别对象是瞬态的还是分离的?

5 个答案:

答案 0 :(得分:12)

听起来你正在寻找EntityManager#contains(Object)

  

检查实例是否是属于当前持久性上下文的托管实体实例。

答案 1 :(得分:4)

Matt建议只检查给定对象是暂时的还是与某个实体管理器相关联。

如果你想检查它是分离的还是瞬态的(你不应该真正关心它!它应该是透明的)你需要检查给定的对象是否有ID。

if(data.getID() == null) return TRANSIENT;

只应为持久/分离对象设置ID。如果由于某种原因你自己在瞬态对象上设置ID,那么我认为你不想做你想做的事。

如果您不知道哪个字段是ID(由于某种原因),或者您想使其成为通用字段,您可以尝试:

ClassMetadata metadata = HibernateUtil.getSessionFactory().getClassMetadata(data.getClass());
if(metadata.getIdentifier(data) == null) return TRANSIENT;

答案 2 :(得分:3)

为了检查对象e是否在: -

  1. 持久化上下文: - EntityManager.contains(e)应该返回true。

  2. 分离状态:PersistenceUnitUtil.getIdentifier(e)返回实体标识符属性的值。

  3. 瞬态: - PersistenceUnitUtil.getIdentifier(e)返回null

  4. 您可以从EntityManagerFactory转到PersistenceUnitUtil。

    有两个问题需要注意。首先,请注意标识符值可能不会 被分配并可用,直到刷新持久性上下文。二,Hibernate (与其他一些JPA提供者不同)永远不会从Persistence-返回null UnitUtil#getIdentifier()如果您的标识符属性是基元(长而不是 很长)。

答案 3 :(得分:1)

您可以尝试传递一个瞬态对象和一个分离的对象以休眠会话更新方法并观察差异。对于瞬态对象,hibernate将报告错误。

因此,休眠知道对象是瞬时的还是分离的。但是如何?答案很简单:在更新之前,hibernate会进行选择,以获取有关哪些字段肮脏的信息。如果对象是瞬时对象,那么选择操作将不会有任何结果,然后休眠知道该对象是瞬时对象并报告错误。

或者,如果您使用@SelectBeforeUpdate(false),hibernate将不执行选择,而是直接进行更新,在这种情况下,由于不需要更新的行,jdbc将报告错误。

当然,您可以检查id字段是否由数据库生成,否则知道其状态的唯一方法是执行查询:未找到表示瞬态。

答案 4 :(得分:0)

正如其他人所说,org.hibernate.Session.contains(Object)可以在Hibernate中用于了解实体实例是已附加还是已分离。关于瞬态,我认为可以做的最好的事情就是org.hibernate.Session.saveOrUpdate(Object)(借助于org.hibernate.persister.entity.AbstractEntityPersister.isTransient(Object, SessionImplementor)),即:

  • 如果该实体不具有@Id属性,则它总是被认为是暂时的
  • 如果实体的@Id属性值为null,则总是被认为是瞬态的
  • 如果实体的@Id属性值等于已配置的unsaved-value,则将其视为瞬态的(仅适用于XML映射,我认为它已过时,请参见here
  • 如果它具有一个@Version属性,其值是新创建的实例之一(即,它是null LongDate等) ,那么它被认为是瞬时的

因此,我认为,对于没有生成ID的实体,可以考虑使用@Version属性。如果没有这样的属性,则saveOrUpdate中的Hibernate本身会对数据库进行SELECT查询,以确定实体实例是否是瞬态的,以确定应分别执行INSERT还是UPDATE。

请参见Hibernate手册(例如4.3 one here)。