如何在 JPA 中明确声明实体是新的(瞬态的)?
How to explictly state that an Entity is new (transient) in JPA?
我正在使用 Spring 数据 JpaRepository
,将 Hibernate 作为 JPA 提供程序。
通常直接使用 Hibernate 时,EntityManager#persist()
和 EntityManager#save()
之间的决定由程序员决定。对于 Spring 个数据存储库,只有 save()
。我不想在这里讨论利弊。让我们考虑以下简单的基础 class:
@MappedSuperclass
public abstract class PersistableObject {
@Id
private String id;
public PersistableObject(){
this.id = UUID.randomUUID().toString();
}
// hashCode() and equals() are implemented based on equality of 'id'
}
使用此基础 class,Spring 数据存储库无法判断哪些实体是 "new"(尚未保存到数据库),因为 [=16] 的定期检查=]显然在这种情况下不起作用,因为UUID被急切地分配以确保equals()
和hashCode()
的正确性。所以存储库似乎做的是总是调用 EntityManager#merge()
- 这对于瞬态实体来说显然是低效的。
问题是: 我如何告诉 JPA(或 Spring 数据)一个实体是新的,这样它使用 EntityManager#persist()
而不是#merge()
如果可能的话?
我一直在考虑这些问题(使用 JPA 生命周期回调):
@MappedSuperclass
public abstract class PersistableObject {
@Transient
private boolean isNew = true; // by default, treat entity as new
@PostLoad
private void loaded(){
// a loaded entity is never new
this.isNew = false;
}
@PostPersist
private void saved(){
// a saved entity is not new anymore
this.isNew = false;
}
// how do I get JPA (or Spring Data) to use this method?
public boolean isNew(){
return this.isNew;
}
// all other properties, constructor, hashCode() and equals same as above
}
也许你应该添加@Version 列:
@Version
private Long version
对于新实体,它将为空
我想在这里再补充一点。尽管它只适用于 Spring 数据而不适用于一般 JPA,但我认为值得一提的是 Spring 提供了 Persistable<T>
接口,它有两种方法:
T getId();
boolean isNew();
通过实现这个接口(例如在开始的问题 post 中),Spring Data JpaRepositories 将询问实体本身是否是新的,这在某些情况下非常方便案例。
我正在使用 Spring 数据 JpaRepository
,将 Hibernate 作为 JPA 提供程序。
通常直接使用 Hibernate 时,EntityManager#persist()
和 EntityManager#save()
之间的决定由程序员决定。对于 Spring 个数据存储库,只有 save()
。我不想在这里讨论利弊。让我们考虑以下简单的基础 class:
@MappedSuperclass
public abstract class PersistableObject {
@Id
private String id;
public PersistableObject(){
this.id = UUID.randomUUID().toString();
}
// hashCode() and equals() are implemented based on equality of 'id'
}
使用此基础 class,Spring 数据存储库无法判断哪些实体是 "new"(尚未保存到数据库),因为 [=16] 的定期检查=]显然在这种情况下不起作用,因为UUID被急切地分配以确保equals()
和hashCode()
的正确性。所以存储库似乎做的是总是调用 EntityManager#merge()
- 这对于瞬态实体来说显然是低效的。
问题是: 我如何告诉 JPA(或 Spring 数据)一个实体是新的,这样它使用 EntityManager#persist()
而不是#merge()
如果可能的话?
我一直在考虑这些问题(使用 JPA 生命周期回调):
@MappedSuperclass
public abstract class PersistableObject {
@Transient
private boolean isNew = true; // by default, treat entity as new
@PostLoad
private void loaded(){
// a loaded entity is never new
this.isNew = false;
}
@PostPersist
private void saved(){
// a saved entity is not new anymore
this.isNew = false;
}
// how do I get JPA (or Spring Data) to use this method?
public boolean isNew(){
return this.isNew;
}
// all other properties, constructor, hashCode() and equals same as above
}
也许你应该添加@Version 列:
@Version
private Long version
对于新实体,它将为空
我想在这里再补充一点。尽管它只适用于 Spring 数据而不适用于一般 JPA,但我认为值得一提的是 Spring 提供了 Persistable<T>
接口,它有两种方法:
T getId();
boolean isNew();
通过实现这个接口(例如在开始的问题 post 中),Spring Data JpaRepositories 将询问实体本身是否是新的,这在某些情况下非常方便案例。