【问题标题】:Determine if entity is new without checking @Id在不检查 @Id 的情况下确定实体是否是新的
【发布时间】:2015-10-26 18:00:23
【问题描述】:

有没有办法确定给定的例如实体类:

@Entity
class A {

    String name;

}

boolean method(Object anyEntity) {
     // How can I check here, if this entity is completely new    
}

我所说的 new 是指有人调用了 new A() 甚至可能设置了名称,但从未保存或保留。

通常可以检查 id,但我想要一种不需要 id 或 getId() 方法的解决方案。

基本上,这个实体是否已经持久化到数据库中,即使在分离模式下也是如此。

@Version 或 getVersion 也不是令人满意的解决方案。

也许是分离的|| isAttached 可能有效,但我不确定如何在 Hibernates API 上进行调用。

编辑:

另外澄清一下,我不控制实体,所以我不能向它们添加任何字段。解决方案应该尝试利用底层机制来确定这一点。

【问题讨论】:

  • 如果没有id字段怎么办? \@Id 也可以在任何字段上设置,并且不必命名为 id。例如 \@Id 字符串名称;在这里会失败。
  • 不确定这是否可以在分离模式下实现。
  • 如果您使用@Id@Version 的引用类型,为什么id == nullversion == null 不起作用?毕竟,只有当实体被持久化到数据库时才会设置这些字段,这是唯一可以说实例是 new 的情况。
  • 版本不是必需的。也许@id 是,但它不必自动生成,但可以手动设置。
  • JPA 托管实体需要有一个强制性的@Id 字段。如果标识符是手动分配的,那么在不更改实体类和不访问数据库的情况下,无法判断实例是否尚未持久化或已分离。如果您无法更改实体类,则可以使用方面注入字段。此外,请确保一次性将所有必要信息添加到您的问题中。现在,随着答案的出现,您似乎正在添加信息,并且开始看起来您这样做只是为了反驳用户为提供答案而付出的努力。

标签: hibernate jpa entity


【解决方案1】:

您可以检查实体是否由 PersistenceContext 管理

EntityManager.contains(entity)

【讨论】:

  • 另一种方法是检查实体是否是HibernateProxy的实例
  • 是的,也许。虽然不确定这样做。 DefaultEvictEventListener 中的 onEvict 似乎正在从持久性上下文中删除一些东西,包括检查 HibernateProxy。但是,还有一个 else 块表明还有其他情况。
  • SessionImpl中有getIdentifier()方法,但不知道够不够用。
【解决方案2】:

如果任何 API 方法不可用,那么我们可以使用 Listeners: 来实现它。这将适用于 JPA/Hibernate。

如下:

@Transient 
private boolean isNew;

@PostPersist
@PostLoad
public void setWhetherNew() {
    isNew = true;
}   

【讨论】:

  • SessionImpl中有getIdentifier()方法,但不知道够不够用。
【解决方案3】:

您可以使用瞬态字段并使用 Entity-Listeners 来 设置此字段。

@Transient
private boolean persisted;

@PostLoad
@PostPersist
public void setPersisted() {
   persisted=true;
}

然后您可以使用persisted 来判断该实体是否曾经被持久化。

-- 编辑--

@PostLoad 是必需的,以便从数据库加载的已持久化实体也将 persisted 设置为 true。否则,即使可以在数据库中找到它们,它们也会显示为“新”。

【讨论】:

  • 为什么需要@PostLoad?
  • 如果你在持久化后从数据库中检索实体,persisted会被设置为true吗?
  • 如果字段是瞬态的,则不会持久化到数据库中。
  • 如果有人使用新关键字创建实体,然后手动将 id 设置为现有的,这将不起作用...
  • 我认为@PostPersist 更合适,因为此调用将在执行实际数据库 INSERT 后调用。
【解决方案4】:

经过对Hibernate源代码的一些工作和分析,我相信这就是答案:

boolean isNew(T entity) {
        return ((SessionImplementor) session()).getPersistenceContext().getEntry(entity) == null;
}

另一方面,在不依赖实现的情况下获取 id 可以这样完成:

    boolean hasId(Object entity) {
            return getId(entity) != null;
    }

    Serializable getId(Object entity) {
            ClassMetadata metadata = metadata(entity);
            if ( metadata.hasIdentifierProperty() ) {
                    return metadata.getIdentifier(entity);
            }
            return null;
    }

    ClassMetadata metadata(Object entity) {
            return getRepository().session().getSessionFactory().getClassMetadata(entity.getClass());
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-06-27
    • 1970-01-01
    • 1970-01-01
    • 2014-04-01
    • 2022-10-14
    • 2019-11-24
    • 1970-01-01
    • 2020-01-11
    相关资源
    最近更新 更多