如何在JPA / Hibernate中判断一个实体是否已分离?

53

有没有办法查询JPA EntityManager是否已将给定实体分离?这篇SO帖子讨论了类似的问题,但没有指示如何查询JPA EntityManager关于实体分离状态的信息。我更喜欢使用JPA方式,否则使用Hibernate特定的方法。


3
你试过使用 EntityManager#contains(-) 吗? - Piotr Nowicki
是的,这似乎可以工作。我正在寻找更明确的内容,但JavaDoc很清楚:“检查实例是否为属于当前持久性上下文的托管实体实例。” - Marcus Junius Brutus
很好,为了保持清晰,我已将此作为答案添加。 - Piotr Nowicki
2个回答

50

36
这不是正确的答案。原因是:contains()方法返回false,确实表示该实体已分离,但在其他情况下也会返回false。按照规范,contains()方法检查给定的实体是否受管理,而分离实体只是导致实体未受管理的几种情况之一。 - MRalwasser
正如@MRalwasser所说:在Hibernate 5上是否仍然是这种情况?还是自回答发布以来已经改变了?并且是在哪个版本中改变的? - Pwnstar

31

Piotr Nowicki的答案提供了一种确定实体是否被管理的方法。要找出实体是否已经分离,我们需要知道它以前是否被管理(即来自数据库,例如通过持久化或从find操作获取)。Hibernate不提供“实体状态历史记录”,因此简短的回答是没有100%可靠的方法来做到这一点,但以下解决方法在大多数情况下应该足够:

public boolean isDetached(Entity entity) {
    return entity.id != null  // must not be transient
        && !em.contains(entity)  // must not be managed now
        && em.find(Entity.class, entity.id) != null;  // must not have been removed
}
上述假设了emEntityManagerEntity是实体类并具有公共的id字段,该字段是一个@GeneratedValue主键。(它还假设在实体被分离后,在数据库表中具有该ID的行没有被外部进程移除。)

这不符合要求 - Pwnstar
有进一步的详细信息吗? - Steve Chambers
1
在我的情况下,我试图更新(合并)的实体始终是“分离的”。最终,我用try catch块包装了“.merge()”,检查IllegalArgumentException,如果它是分离的,则会出现该异常。 - Pwnstar
1
另外,我认为IllegalArgumentException不是“对象已从PersistenceContext分离”的正确异常类型 :-) - Pwnstar
1
@Enerccio 第三个条款是要找出实体行是否仍然存在于数据库中,否则它可能是尚未持久化的新行。请查看答案的最后一句话以了解有关此事项的警告。 - Steve Chambers
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接