让我们假设一个简单的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将看到两个碰巧共享同一列的关系。然而,据我所知,它应该起作用。
我曾经看到过一个不合理的引用,它可能会导致性能问题,但我再也找不到那个引用了,所以我不确定。它会有两个问题,哪种问题证明了选项的"这不是你真正应该做的"性质:
- 在关闭事务/会话并从数据库中重新加载子实体之前,不会更新父字段
- 如果您以后决定实现二级缓存,它可能会更改代码的逻辑。这是因为子实体可能在一段时间内不会从数据库中重新加载,并且在重新加载之前,父字段将为null
您可以通过动态代理和反射自己实现这一点,尽管您必须通过DAO/Repository控制实体的创建,以确保它们被代理。
最后,我个人不会推荐它。我年纪越大,就越觉得你的应用程序中的黑魔法越少越好。