【问题标题】:How to identify an object is transient or detached in hibernate?如何识别对象在休眠中是瞬态的还是分离的?
【发布时间】:2013-10-20 06:00:42
【问题描述】:

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

是否有任何方法可以使用 Session 上的任何方法或以编程方式在休眠中使用其他方法来识别对象是瞬态的或分离的?

【问题讨论】:

    标签: hibernate


    【解决方案1】:

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

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

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

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

    您可以从 EntityManagerFactory 访问 PersistenceUnitUtil。

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 感谢马特的回复。但我认为它会检查此实例是否与持久上下文相关联,对吗?我猜它类似于休眠中的 session.contains(object)。
      【解决方案3】:

      你可以尝试将一个transient object和一个detached object传递给hibernate session update方法并观察区别。对于transient object,hibernate会报错。

      所以休眠知道对象是瞬态的或分离的。但是怎么做?答案很简单:hibernate 会在更新前做一个 select 来获取哪些字段是脏的信息。如果对象是瞬态的,则该选择操作将没有结果,然后休眠知道这是瞬态对象并报告错误。

      或者,如果你使用@SelectBeforeUpdate(false),hibernate不会做select,而是直接更新,这种情况下jdbc会因为需要更新的行不存在而报错。

      当然,你可以检查 id 字段是否由数据库生成,否则了解其状态的唯一方法是进行查询:未找到意味着暂时的。

      【讨论】:

        【解决方案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;
        

        【讨论】:

        • @MateuszDymczyk 我没有投反对票,但如果你创建一个对象并手动设置它的 ID,它仍然是暂时的,我认为大多数人都会遇到这种情况(像我一样,我从 JSON 解码中获取我的对象)
        • @MateuszDymczyk 另外,getClassMetadata 是反射,它有自己的性能损失,恕我直言,您应该在回答中明确说明。
        【解决方案5】:

        正如其他人所说,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)。

        【讨论】:

          猜你喜欢
          • 2011-02-04
          • 2011-05-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-23
          相关资源
          最近更新 更多