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 单向映射...级联删除的主要内容,如果未能解决你的问题,请参考以下文章

学说 oneToOne 单向:获取映射对象

Hibernate入门之one to one关系映射详解

为啥在这个 Hibernate 映射中使用 @ManyToOne 而不是 @OneToOne?

Hibernate @OneToOne 映射不加入列?

03-hibernate注解-关系映射级别注解

在 Hibernate / JPA 2.1 中延迟加载的 @OneToOne 映射不起作用?