【问题标题】:Spring Data JPA Repository with Hibernate - persist (sql insert) parent entity but only update nested child entities带有 Hibernate 的 Spring Data JPA 存储库 - 持久化(sql 插入)父实体,但仅更新嵌套的子实体
【发布时间】:2017-10-04 22:53:27
【问题描述】:

我正在开发一个包含 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;
}

以下是我在应用中执行的步骤:

  1. 从回购中拉出B;如果存在,请更新其某些字段值 [或] 使用字段值创建新的 B
  2. 创建A 的新实例并将B 设置为A
  3. 坚持A(通过调用JpaCrudRepository.save(A))。

成功部分: 当 B 在 repo 中不存在时,一切正常。这意味着:

  1. 创建了B(和CDE)的新实例,
  2. 这个新创建的B被设置成A
  3. 并且A 已成功持久化到 repo(在 DB/repo 的所有对应表中插入新行)。

失败部分:

  1. 现在,当B 已经存在于repo 中时,现有的B 会被正确拉取,
  2. B 的某些字段已更新,而 CDE 保持不变,
  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 存储库没有明确可用的 merge() 或 update() 操作,而 save() 应该涵盖这些操作。如果实体实例已经存在,则此 save() 操作通过调用 merge() 或者如果它是新的,则通过调用 persist() 来工作。进一步挖掘,实体的 ID 列被用来确定它在 repo 中的存在。如果此 ID 为 null,则实体被确定为新实体,如果 ID 不为 null,则实体被确定为现有。

所以在我上面的失败案例中,由于现有的 B 实体实例正在从 repo 中提取,它已经有一个非空 ID。

所以我目前还不清楚我在这里缺少什么。 我尝试在网上找到任何匹配的解决方案,但还没有找到。

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

【问题讨论】:

  • 向我们展示A - E 的代码,仅包括关联(不需要其他属性)。
  • 感谢收看!我在帖子中添加了模型 [A 到 E]。
  • 这个问题还不清楚。你说当B 已经存在时,CDE 保持不变,但是你在DE 上得到一个唯一的约束违规,这只会在尝试插入时发生在DE 上,根据您的说法,没有尝试过。这听起来不对。这是您的应用程序特有的调试问题。

标签: spring hibernate jpa orm spring-data


【解决方案1】:

找到问题和解决方案。由于 A 和 B 被创建为新的,因此 C、D、E 都被创建为新的,这导致了违规。所以为了解决这个问题,我必须从数据库中提取每个现有的 C、D 和 E 实体,并在新创建的 B 实体中分别/分层设置它们,然后再尝试持久化。

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

【讨论】:

    猜你喜欢
    • 2021-06-26
    • 1970-01-01
    • 2016-06-17
    • 2014-10-20
    • 2011-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-20
    相关资源
    最近更新 更多