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(),但我不确定这是否足够。