Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Hibernate 在不检查@Id的情况下确定实体是否为新实体_Hibernate_Jpa_Entity - Fatal编程技术网

Hibernate 在不检查@Id的情况下确定实体是否为新实体

Hibernate 在不检查@Id的情况下确定实体是否为新实体,hibernate,jpa,entity,Hibernate,Jpa,Entity,是否有一种方法可以确定给定的实体类: @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()方法的解决方案 基本上,这个

是否有一种方法可以确定给定的实体类:

@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()方法的解决方案

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

@版本或getVersion也不是令人满意的解决方案

也许isDetached | | isAttached可以工作,但我不确定如何在HibernatesAPI上进行调用

编辑:


还要澄清的是,我不控制实体,因此我不能向它们添加任何字段。解决方案应该尝试利用底层机制来确定这一点

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

EntityManager.contains(entity)

如果任何API方法不可用,那么我们可能可以使用侦听器实现它:。这将在JPA/Hibernate上运行。

如下图所示:

@Transient 
private boolean isNew;

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

您可以使用临时字段并使用实体侦听器 设置此字段

@Transient
private boolean persisted;

@PostLoad
@PostPersist
public void setPersisted() {
   persisted=true;
}
然后,您可以使用
持久化
来判断实体是否已持久化

--编辑--


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

经过一些工作和对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());
    }

如果它没有id字段怎么办\@Id也可以在任何字段上设置,并且不必命名为Id;将在此失败。不确定是否可以在分离模式下实现此操作。如果将引用类型与
@Id
@Version
一起使用,为什么
Id==null
Version==null
不起作用?毕竟,只有当实体被持久化到数据库时,才会设置这些字段,这是唯一一种您会说实例是
new
。版本不是必需的情况。@id可能是,但它不必自动生成,但可以手动设置。JPA管理的实体需要有一个必填的
@id
字段。如果标识符是手动分配的,则在不更改实体类和不命中数据库的情况下,无法判断实例是否尚未持久化或已分离。如果不能更改实体类,可以使用方面注入字段。此外,请确保您一次性将所有必要信息添加到问题中。现在,随着答案的出现,您似乎正在添加信息,而且您这样做似乎只是为了反驳用户为提供答案所付出的努力。另一种方法是检查实体是否是HibernateProxy的实例,也许是。不过我不确定要这么做。DefaultReceiveEventListener中的onEvict似乎正在从持久性上下文中删除一些内容,包括检查HibernateProxy。但是,还有一个else块表明还有其他情况。SessionImpl中有getIdentifier()方法,但我不确定它是否足够。为什么需要@PostLoad?如果在持久化后从数据库检索实体,是否将
持久化
设置为true?如果字段是暂时的,它不会在数据库中持久化。如果有人使用新关键字创建实体,然后手动将id设置为现有id,则此操作无效…我认为@PostPersist更合适,因为此调用将在实际执行数据库插入后调用。SessionImpl中有方法getIdentifier(),但我不确定这是否足够。