2017-05-06 62 views
1

我正在开发Spring数据,JPA,Hibernate组合的Spring Boot应用程序。下面是我正在努力的方案,预期的行为是只更新一些子实体,而父实体被插入为新实体。Spring数据与Hibernate JPA仓库 - 坚持(SQL插入)父实体,但只更新嵌套的子实体

实体类

@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; 
} 

下面是我执行的应用程序的步骤:从回购

  1. B;如果存在,则更新其某些字段值[或]用字段值创建新的B
  2. 创建A的新实例并将B设置为A
  3. 坚持A(调用JpaCrudRepository.save(A))。

成功部分: 一切正常,当B不存在回购已经。这意味着:

  1. 创建B(和CDE)的新实例,
  2. 这个新创建的B被设置为A
  3. A仍保持为成功回购(新行插入DB/repo中的所有对应表中)。

故障部位:

  1. 现在,当B在回购已经存在,现有B适当拉,而CDE都保持不变
  2. B某些字段被更新,
  3. 而此更新的B设置为A
  4. 但是,当试图持续A现在在DE上引发唯一约束冲突。

所有实体均标有以下几点:

• 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的库没有合并()或update()操作明确可用,并且save()应该覆盖这些操作。这个save()操作通过调用merge()来实现,如果实体实例已经存在的话,或者如果它是新的,则调用persist()。并且进一步挖掘,实体的ID列正被用于确定其在回购中的存在。如果该ID为空,则实体被确定为新的,并且如果ID不为空,则存在实体。

因此,在我上面的失败案例中,由于现有B实体实例正在从回购中拉出,因此它已具有非空ID。

所以我目前不清楚我在这里错过了什么。 我尝试过在网上找到任何匹配的解决方案,但还是无法到达。

有人能帮我找出我的方法有什么问题吗?

+0

向我们展示'A' - 'E'的代码,仅包括关联(不需要其他属性)。 – manish

+0

感谢您的期待!我在帖子中添加了模型[A到E]。 – Ram

+1

这个问题还不清楚。你说当'B'已经存在时,'C','D'和'E'保持不变,但是你在'D'和'E'上得到一个唯一的约束违反,这只有在尝试插入时才会发生在'D'和'E'上,根据你的要求没有被尝试。这听起来不对。这是一个特定于您的应用程序的调试问题。 – manish

回答

0

发现问题和解决方案。由于A和B被创建为新的,因此C,D,E都被创建为新的,从而导致违规。因此,为了解决这个问题,我必须从DB中提取C,D和E中的每个现有实体,并在尝试持久化之前分别在新创建的B实体内设置它们。

基本上,如果实体嵌套在将要被持久化的父实体内,则不要为实体创建新实例..并且目标是在类似记录已存在时进行更新。