Hibernate @OneToOne 单向映射...级联删除
Posted
技术标签:
【中文标题】Hibernate @OneToOne 单向映射...级联删除【英文标题】:Hibernate @OneToOne Unidirectional Mapping...Cascade Delete 【发布时间】:2021-07-28 18:08:32 【问题描述】:我正在使用 Hibernate 开发 Spring Boot 应用程序,我只是想了解在使用级联删除时处理 OneToOne 映射的正确方法。
所以,我们有一个 User 表和一个 PasswordResetToken 表。用户具有标准用户列:id、用户名、密码、电子邮件。
密码重置令牌有一个 id、一个到 userId 的 FK 和一个用于令牌的字符串。
所以,我现在的问题是:我如何正确地对此建模,以便我们可以正确地级联删除?
我的想法是我们有一个单向映射,因为密码重置令牌对用户有一个 FK,而用户没有密码重置令牌的 FK。
所以我认为我们会将@OneToOne 放在Java 中的PasswordResetToken 类中,并且在我们的User 类中没有对PasswordResetToken 的引用,但是PasswordResetToken 类将具有对User 对象的引用。
但是,通过一些***ing,我发现尽管父对象的表没有对子对象的表的引用(因为用户表没有其中有一个 PasswordResetToken),它允许将级联删除添加到 @OneToOne 注释,这意味着当用户被删除时,所有子项也将被删除。
那么,建立这种关系的正确方法是什么?
感谢您的宝贵时间
【问题讨论】:
【参考方案1】:有很多方法可以解决您的问题。有些更少,有些更高效。
带外键的双向
@Entity
public class PasswordResetToken
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User User;
// other fields
@Entity
public class User
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL,
fetch = FetchType.LAZY, optional = false)
private PasswordResetToken passwordResetToken;
// other fields
以principal/parent的主键作为外键的双向
由于是 1-1 关系,您可以使用 User
的 ID 作为 PasswordResetToken
表的主键。
@Entity
public class PasswordResetToken
@OneToOne(fetch = FetchType.LAZY)
@MapsId
private User User;
// other fields
@Entity
public class User
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL,
fetch = FetchType.LAZY, optional = false)
private PasswordResetToken passwordResetToken;
// other fields
单向
如果您想进行单向映射,并将PasswordResetToken
实体作为User
实体的一部分,您必须将外键移动到User
表,因为@JoinColumn
必须应用于拥有外键的实体。
@Entity
public class User
@OneToOne(cascade = CascadeType.ALL,
fetch = FetchType.LAZY)
@JoinColumn("password_reset_token_id") // FK in User table
private PasswordResetToken passwordResetToken;
// other fields
至于性能,最高效的是双向@MapsId
。 @JoinColumn
的双向效率较低,我不确定单向映射。一对一映射在实践中并不常见,我不确定人们使用单向映射的频率。可能根本没有,因为外键通常在依赖端。
【讨论】:
谢谢,我目前正在使用单向方法,因为我听说双向可能效率低下。但是,我很困惑,因为在我的 User 表中,我没有对 passwordResetToken 对象的引用。但是在我的 Java 类中,我们创建了对它的引用吗?我对此有点困惑,我不应该将两者进行比较吗? 其实双向映射效率更高。您可以使用来自this post 的this image 作为参考指南。此外,您不应该将 DB 模型与对象模型进行比较(ORM 可以克服这些差异)。即使您在 User 表中没有 FK,您也可以告诉 Hibernate 如何创建您需要的对象。例如,在双向映射中,您在具有 FK 的实体中拥有@JoinColumn
,然后在其他实体中使用 mappedBy
。
另外,这取决于您拥有的数据。如果您在 Post 和 Comment 之间有一对多的关系(例如)并且您想要获取具有 10000 条评论的 Post,那么双向映射的效率会降低,因为它需要从 DB 中获取太多数据并存储它在对象中。使用 HIbernate(或任何其他 ORM)时,您应该始终考虑要处理的数据量并相应地调整映射。
啊,是的,我一直在比较 DB 模型和对象模型。下次我会把它们分开!是的,所以这取决于您的数据。谢谢你的详细解释!【参考方案2】:
我不知道令牌有多大,但是将令牌存储在User
实体中作为简单列有什么问题?您可以使用@Embeddable
抽象某些部分,但实际上这应该 IMO 在同一个表中。如果您关心获取的数据量,您应该使用 DTO 来减少数据量。
【讨论】:
我想我可以,但为了学习目的,我想尽可能多地分开表格。以上是关于Hibernate @OneToOne 单向映射...级联删除的主要内容,如果未能解决你的问题,请参考以下文章