如何知道一个分离的 JPA 实体是不是已经被持久化?

Posted

技术标签:

【中文标题】如何知道一个分离的 JPA 实体是不是已经被持久化?【英文标题】:How to know if a detached JPA entity has already been persisted or not?如何知道一个分离的 JPA 实体是否已经被持久化? 【发布时间】:2011-02-16 07:34:39 【问题描述】:

我的应用程序的 Web UI 层中有一个 JPA 实体实例。我想随时知道这个实体是否已经保存在数据库中,或者它是否只存在于用户会话中。

它将在业务层中,我会使用 entitymanager.contains(Entity) 方法,但在我的 UI 层中,我认为我需要一个额外的属性来指示实体是否已保存。如何实施?我目前正在考虑以下选项:

一个 JPA 属性,其默认值由数据库设置,但会在每次更新后强制重新读取? 在我的代码中手动设置或由 JPA 自动设置的非 JPA 属性?

有什么建议/其他建议吗?

我正在使用 JPA 1 和 Hibernate 3.2 实现,并希望坚持标准。

【问题讨论】:

【参考方案1】:

首先,让我们提醒一下实体的各种状态。来自 JPA 1.0 规范(在第 3.2 节实体实例的生命周期中):

本节介绍 用于管理的 EntityManager 操作 实体实例的生命周期。一个 实体实例可以被表征 作为新的、托管的、分离的或 删除。

实体实例没有持久性身份,目前还没有 与持久化上下文相关联。 托管实体实例是具有持久标识的实例 当前与持久性上下文相关联。 分离的实体实例是具有持久标识的实例 不(或不再)与持久性上下文相关联。 已删除实体实例是具有持久身份的实例,与持久上下文相关联,计划从数据库中删除。

还有一个图解:

所以,根据定义,一个分离的实体已经被持久化了,我实际上不认为这是你真正的问题。现在,如果您想知道一个实体是否是新的(即没有任何持久身份),那么这个呢:

@Transient
public boolean isNew() 
    return (this.id == null);

【讨论】:

当然,我想知道我的实体是否是新的。我宁愿使用在数据库中设置了默认值的另一个字段,因为我没有对主键使用 JPA GeneratedValue 策略(我正在为自己设置带有 UUID 的主键,以实现跨数据库供应商/jpa 实现/集群兼容性)。 @snowflake 问题是 JPA 不支持非 pk 属性的数据库生成值,因此您必须使用 JPA 提供程序扩展(如 @org.hibernate.annotations.Generated)或在持久后刷新实体,这是丑陋的。我想知道使用@GeneratedValue 是否不是更好的选择。 感谢您的评论。没错,这很丑陋,我更喜欢使用我的 DAO 中设置的字段作为替代。 某处我读到了关于使用默认值为 null 的@Version。您可以检查是否 version != null 因为它应该在每次写入时更新。但是,我看到的例子是使用 xml。自己还没有测试过(还) 如何检查分离的实体是否已更改(不仅是新实体。)?

以上是关于如何知道一个分离的 JPA 实体是不是已经被持久化?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法将分离的对象传递给 JPA 持久化? (分离的实体传递给坚持)

JPA:传递给持久化的分离实体:嵌套异常是 org.hibernate.PersistentObjectException

从 JPA/EJB3 持久性上下文中分离实体

带有 JPA/EJB 代码的“分离实体传递给持久错误”

Spring Data JPA:一对一实例化问题:PersistentObjectException:分离实体传递给持久化

删除分离实体spring jpa Repository接口