我正在使用Spring数据,JPA,Hibernate组合开发Spring Boot应用程序。下面是我正在努力解决在将父实体作为新插入父实体时仅更新某些子实体的预期行为的情况。
实体类
@Entity
public class A {
@Id
private long id;
@ManyToOne
@JoinColumn (name = "B_ID")
@Cascade ( { CascadeType.ALL } )
private B b;
}
@Entity
@DynamicUpdate
public class B {
@Id
private long id;
@OneToMany (mappedBy = "b")
@Cascade ( { CascadeType.ALL } )
private Set<A> as;
@ManyToOne
@JoinColumn (name = "C_ID")
@Cascade ( { CascadeType.ALL } )
private C c;
}
@Entity
@DynamicUpdate
public class C {
@Id
private long id;
@OneToMany (mappedBy = "c")
@Cascade ( { CascadeType.ALL } )
private Set<B> bs;
@ManyToOne
@JoinColumn (name = "D_ID")
@Cascade ( { CascadeType.ALL } )
private D d;
@ManyToOne
@JoinColumn (name = "E_ID")
@Cascade ( { CascadeType.ALL } )
private E e;
}
@Entity
@DynamicUpdate
public class D {
@Id
private long id;
@OneToMany (mappedBy = "d")
@Cascade ( { CascadeType.ALL } )
private Set<C> cs;
}
@Entity
@DynamicUpdate
public class E {
@Id
private long id;
@OneToMany (mappedBy = "e")
@Cascade ( { CascadeType.ALL } )
private Set<C> cs;
}
以下是我在应用中执行的步骤:
B
;如果存在,则更新其某些字段值[或]使用字段值创建新的B
。A
的新实例并将B
设置为A
。A
(通过调用JpaCrudRepository.save(A)
)。 成功部分:
当B
已经存在于repo中时,一切正常。这意味着:
B
(和C
,D
,E
)的新实例,B
设置为A
,A
持续成功回购(在DB / repo的所有相应表中插入新行)。失败部分:
B
时,现有B
已正确拉出,B
,C
,D
保持不变的情况下更新了E
的某些字段,B
已设置为A
。A
时,D
和E
会抛出唯一约束违规。所有实体都标有以下内容:
• ID as auto-generated column (used as PK implicitly),
• Mapping between entities using the ID column,
• CascadeType ALL wherever mappings like OneToMany, ManyToOne are applied,
• Dynamic update annotation.
到目前为止,我可以通过网络收集有关此主题的内容:
JPA资源库没有显式提供merge()或update()操作,而save()应该涵盖这些操作。如果实体实例已经存在,则此save()操作通过调用merge()或者通过调用persist()(如果它是新的)来工作。进一步挖掘,实体的ID列用于确定它在回购中的存在。如果此ID为null,则将entity确定为new,如果ID不为null,则将其确定为现有。
因此,在我上面的失败案例中,由于从repo中提取现有的B
实体实例,因此它已经具有非空ID。
所以我目前还不清楚我到底错过了什么。 我尝试在网上找到任何匹配的解决方案,但还没有到达。
有人可以帮我确定一下我的做法有什么问题吗?
答案 0 :(得分:0)
找到问题和解决方案。由于A和B被创建为新的,随后C,D,E都被创建为新的,导致违规。因此,为了解决这个问题,我必须从数据库中提取C,D和E中的每个现有实体,并在尝试持久化之前,在新创建的B实体内分别/分层设置它们。
基本上,如果实体嵌套在即将保留的父实体中,则不要为该实体创建新实例。目标是在类似记录已存在时更新。