如何明确说明实体在JPA中是新的(瞬态)?

Ala*_*n47 3 spring hibernate jpa spring-data-jpa

我使用Spring Data JpaRepository,Hibernate作为JPA提供者.

通常直接与Hibernate之间的决策工作时EntityManager#persist(),并EntityManager#save()是由程序员.使用Spring Data存储库,只有save().我不想在这里讨论利弊.让我们考虑以下简单的基类:

@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'
}
Run Code Online (Sandbox Code Playgroud)

使用此基类,Spring Data存储库无法分辨哪些实体是"新的"(尚未保存到DB),因为id == null在这种情况下,定期检查 显然不起作用,因为UUID被热切地分配以确保正确性中equals()hashCode().因此,存储库似乎总是调用EntityManager#merge()- 这对于瞬态实体来说显然效率低下.

问题是:我如何告诉JPA(或Spring Data)实体是新的,以便它使用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

}
Run Code Online (Sandbox Code Playgroud)

小智 5

也许您应该添加@Version列:

@Version
private Long version
Run Code Online (Sandbox Code Playgroud)

如果是新实体,则为null


Ala*_*n47 5

我想在这里再补充一点.虽然它只适用于Spring Data而不适用于一般JPA,但我认为值得一提的是Spring提供了Persistable<T>接口,它有两种方法:

T getId();
boolean isNew();
Run Code Online (Sandbox Code Playgroud)

通过实现此接口(例如在开放问题帖子中),Spring Data JpaRepositories将询问实体本身是否是新的,在某些情况下这可能非常方便.