【问题标题】:How to save bidirectional association without cascading using Spring data JPA?如何在不使用 Spring 数据 JPA 级联的情况下保存双向关联?
【发布时间】:2014-09-17 14:37:55
【问题描述】:

假设我在父子之间有双向的一对多关联,映射如下:

父.java:

@Entity
public class Parent {

    @Id
    private Integer id;

    @OneToMany(mappedBy = "parent")
    private List<Child> childs = new ArrayList<>();
    ...

和 Child.java:

@Entity
public class Child {

    @Id
    private Integer id;

    @ManyToOne
    @JoinColumn(name = "parent_id")
    private Parent parent;

    ...

当我运行这段代码时

    Parent parent = new Parent(1);
    Child child = new Child(1);
    Child child2 = new Child(2);
    child.setParent(parent);
    child2.setParent(parent);
    parent.getChilds().add(child);
    parent.getChilds().add(child2);

    parentRepository.save(parent);

我得到异常

    Unable to find Child with id 1

先救孩子也无济于事,只有例外不同

【问题讨论】:

  • 好吧,这里有一些澄清:
  • 我需要保存父级而不保存子级,这就是不需要级联的原因。在我的情况下,瞬态不是一个解决方案,我仍然希望孩子们急切地加载父级负载。因此,如果没有级联,Spring JPA(或休眠持久性提供者,不确定哪个负责)正在检查每个孩子的持久性。如果我无论如何都不会保存它们(或稍后会保存),那么检查的意义何在?
  • 为什么要在持久化父级之前将子级添加到父级,但又不想持久化它们? - 如何首先持久化父实体,然后使用持久化父实体,根据需要添加子实体?完成后,您将merge() 新父级的状态(包括子级)写入数据库。
  • 这一切都是因为我没有与数据库保持一致的同步,假设我的实体可以及时改变,如果我有 1000 个孩子的父母,没有级联我只是检查孩子是否被改变(它有一个额外的布尔属性)并只保存/合并它。如果我使用 cascade 它会通过请求数据库检查每 1000 个孩子(我不是在谈论那里的其他关系),那就是很多数据库请求!
  • 我认为这只是部分正确。只要您使用单个持久性上下文并且不从其中分离持久性实体,对象就会“附加”到它。这意味着上下文将能够(通过代理对象或检测)准确地确定自上次与数据库同步以来哪个持久对象的哪个属性发生了变化,并且只保留/合并那些,而无需额外的回合-去数据库。这基本上意味着持久性提供程序已经管理并使用了一个内部标志来让您注意哪些对象是“脏的”w.r.t。数据库。

标签: java spring hibernate jpa


【解决方案1】:

我很抱歉发布了一个不确定的答案,但我不能发布评论的声誉原因。 我认为您有一个交叉引用问题,因为只需从孩子那里引用父母,您就可以通过简单的查询获得父母拥有的孩子。相反,您交叉引用导致许多对象问题的子关联。如果您愿意,我可以向您发布一个类图以获得更好的解释。希望对你有帮助

【讨论】:

  • 不,这是一个完全正确的双向关联(我错了吗?)。
  • 让我们说没关系,并尝试考虑简单的用例。第一种情况:您想添加一个具有空子列表的父级,这将起作用;第二种情况:您想添加一个具有空父级的子级,这也将起作用,现在在您发布的案例中,您正在初始化一个父对象,请引用它有 2 个孩子,然后您尝试使用未保存的子实体保存父实体,因此休眠无法找到它们与您首先尝试使用未保存的父引用保存子实体的相反情况相同
  • 那么,我们得到的是:如果没有级联,双向关联将永远无法工作?
  • 如果您按照 Hanno Binder 在上面的评论中发布的解决方案,您可以在没有级联的情况下做到这一点
【解决方案2】:

试试

@OneToMany(mappedBy = "parent", cascade={CascadeType.PERSIST})
private List<Child> childs = new ArrayList<>();

(例如,另请参阅JPA @ManyToOne with CascadeType.ALL

【讨论】:

  • 正如我所说,我想让它在没有任何级联的情况下工作,所以,对不起,但它没有回答我的问题
猜你喜欢
  • 2022-11-28
  • 1970-01-01
  • 2017-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-02
  • 1970-01-01
相关资源
最近更新 更多