添加到@ManyToOne时更新父引用



让我们假设一个简单的1父->n子实体关系(省略getters/ssetters):

@Entity
public class Father {
    @Id
    @GeneratedValue
    private Integer id;
    @OneToMany(mappedBy="father", cascade=CascadeType.ALL)
    private List<Child> children = new ArrayList<>();
    ...
}
@Entity
public class Child {
    @Id
    @GeneratedValue
    private Integer id;
    @ManyToOne(cascade=CascadeType.ALL)
    private Father father;
    ...
}

当现在试图通过简单地向父亲添加一个孩子来更新这种关系时,这是行不通的,因为Child.father不会更新:

Child child = new Child();
// optionally persist child first, tried
father.getChildren().add(child);
...save father

我尝试使用不同的CascadeTypes,但似乎无法自动更新Child.father引用。我知道传统的方法是使用"addChild"方法,但我想知道是否有自动的方法?

我的配置是SpringBoot+JPA(Hibernate)+H2,自动创建到数据库。有趣的是,我发现一些博客文章似乎和我在这里做的一模一样,但对他们来说是有效的,但对我来说不是。奇怪。

是的,但不是有意的。我只是真正解释它,因为它可以解释你在那些博客文章中看到的内容。通过删除mappedBy并添加@JoinColumn,可以使@OneToMany成为关系的拥有方。然而,这主要是针对没有反向引用的情况。如果保留@ManyToOne,那么Hibernate将看到两个碰巧共享同一列的关系。然而,据我所知,它应该起作用。

我曾经看到过一个不合理的引用,它可能会导致性能问题,但我再也找不到那个引用了,所以我不确定。它会有两个问题,哪种问题证明了选项的"这不是你真正应该做的"性质:

  1. 在关闭事务/会话并从数据库中重新加载子实体之前,不会更新父字段
  2. 如果您以后决定实现二级缓存,它可能会更改代码的逻辑。这是因为子实体可能在一段时间内不会从数据库中重新加载,并且在重新加载之前,父字段将为null

您可以通过动态代理和反射自己实现这一点,尽管您必须通过DAO/Repository控制实体的创建,以确保它们被代理。

最后,我个人不会推荐它。我年纪越大,就越觉得你的应用程序中的黑魔法越少越好。

最新更新