到目前为止,我的理解是,级联只有从父级到子级才有意义。现在我想知道:这是否也适用于一对一关系?
我这样问是因为我在我们的代码中发现了许多(单向的)OneToOne关系,它们从子节点级联到父节点。我用“persist”测试了它,它似乎起作用了--这意味着暂时的子节点和暂时的父节点一起被持久化。在查阅文献时,我发现了这样一个级联策略的例子。例如在baeldung上:
// CHILD
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
//...
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "address_id", referencedColumnName = "id")
private Address address;
}
//PARENT
@Entity
@Table(name = "address")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
//...
@OneToOne(mappedBy = "address")
private User user;
}
在其他一些文章中,级联是以相反的方式完成的,例如在Vlad Mihalcea's blog上:
//CHILD
@Entity(name = "PostDetails")
@Table(name = "post_details")
public class PostDetails {
@Id
@GeneratedValue
private Long id;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id")
private Post post;
}
//PARENT
@Entity(name = "Post")
@Table(name = "post")
public class Post {
@Id
@GeneratedValue
private Long id;
@OneToOne(mappedBy = "post", cascade = CascadeType.ALL,
fetch = FetchType.LAZY, optional = false)
private PostDetails details;
}
那么最后它们是两个有效的选择吗?我很困惑。
1条答案
按热度按时间nwsw7zdq1#
首先,我不是一个
CASCADE
的粉丝。为什么?仅仅是因为如果你不知道发生了什么,为什么要使用一个东西?我不能回答你的问题,因为这取决于你认为什么是正确的。但我可以帮助阐明一些问题。
您需要了解“拥有实体”。从Javadoc:
如果关系是双向的,则非拥有方必须使用OneToOne注解的mappedBy元素来指定拥有方的关系字段或属性。
在第一种情况下,
User
是拥有实体。在JPA中,只有拥有方将持久化关系。在这种情况下,只有在User
实体中设置了Address
字段时,JPA才会尝试持久化关系。持久化操作为:
结果是:
没有问题。但是如果
Address
已经持久化了呢?结果:
使用
Cascade
有问题,因为它特灵插入两者,但当前地址已经存在。您可以解决它:这会产生以下可爱的SQL语句:
或者,如果现有地址记录存在,您可以先将其删除,但之后必须先进行检查,依此类推。这是一个不错的解决方案。请确保在事务中执行此操作。
或者你可以完全避免使用cascade,你必须自己保存
Address
和User
,或者使用一个已经保存的示例,这也意味着你必须先检查,但至少你“知道”你在做什么。结果:
那么,你应该把
Cascade
放在哪一边呢?如果你打算坚持使用它,让你的生活变得复杂得多,它应该放在关系的拥有方,在这种情况下是User
。或者,就把它放在一边,开心点。