Spring数据JPA:如何启用级联删除而不引用父级中的子级? [英] Spring data JPA: how to enable cascading delete without a reference to the child in the parent?

查看:670
本文介绍了Spring数据JPA:如何启用级联删除而不引用父级中的子级?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

也许这是一个过于简单的问题,但是当我尝试删除用户实体时,我收到了异常。



用户实体:

  @Entity 
@Table(name =users)
公共类用户
{
@Transient
private static final int SALT_LENGTH = 32;

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;

@NotNull
private String firstName;

@NotNull
private String lastName;

@Column(unique = true,length = 254)
@NotNull
private String email;

// BCrypt输出60个字符的结果。
@Column(length = 60)
private String hashedPassword;

@NotNull
private String salt;

启用私有布尔值;

@CreationTimestamp
@Temporal(TemporalType.TIMESTAMP)
@Column(updatable = false)
private Date createdDate;

我有一个实体类,它引用具有外键的用户。我想要发生的是,当用户被删除时,任何引用该用户的 PasswordResetToken 对象也将被删除。我该怎么做?

  @Entity 
@Table(name =password_reset_tokens)
public class PasswordResetToken
{
private static final int EXPIRATION_TIME = 1; //在几分钟内

private static final int RESET_CODE_LENGTH = 10;

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;

private String token;

@OneToOne(targetEntity = User.class,fetch = FetchType.EAGER)
@JoinColumn(nullable = false,name =userId)
private User user;

private Date expirationDate;

我得到的例外归结为无法删除或更新父行:外键约束失败(`heroku_bc5bfe73a752182` .password_reset_tokens`,CONSTRAINT`FKk3ndxg5xp6v7wd4gjyusp15gq` FOREIGN KEY(`user_id`)REFERENCES`users`(`id`))



我想避免在父实体中添加对 PasswordResetToken 的引用,因为用户不应该知道关于 PasswordResetToken 的任何信息。

解决方案

在没有创建双向关系的情况下,在JPA级别上是不可能的。您需要在用户类中指定级联类型。 用户应该是该关系的所有者,它应该提供有关如何处理相关 PasswordResetToken 的信息。



但如果你不能有双向关系,我建议你直接在模式生成SQL脚本中设置关系。



如果您通过SQL脚本创建架构而不是通过JPA自动生成(我相信所有严肃的项目必须遵循此模式),您可以在那里添加 ON DELETE CASCADE 约束。 / p>

它看起来会像这样:

  CREATE TABLE password_reset_tokens(
- 这里的列声明
user_id INT(11)NOT NULL,
CONSTRAINT FK_PASSWORD_RESET_TOKEN_USER_ID
FOREIGN KEY(user_id)REFERENCES users(id)
ON DELETE CASCADE
);

这是关于如何使用数据库迁移的文档弹簧靴的工具。这里有有关如何从hibernate生成模式脚本的信息(这将简化编写自己脚本的过程)。


Maybe this is an overly simple question, but I am getting an exception when I try to delete a user entity.

The user entity:

@Entity
@Table(name = "users")
public class User 
{
    @Transient
    private static final int SALT_LENGTH = 32;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    @NotNull
    private String firstName;

    @NotNull
    private String lastName;

    @Column(unique = true, length = 254)
    @NotNull
    private String email;

    // BCrypt outputs 60 character results.
    @Column(length = 60)
    private String hashedPassword;

    @NotNull
    private String salt;

    private boolean enabled;

    @CreationTimestamp
    @Temporal(TemporalType.TIMESTAMP)
    @Column(updatable = false)
    private Date createdDate;

And I have an entity class which references a user with a foreign key. What I want to happen is that when the user is deleted, any PasswordResetToken objects that reference the user are also deleted. How can I do this?

@Entity
@Table(name = "password_reset_tokens")
public class PasswordResetToken 
{
    private static final int EXPIRATION_TIME = 1; // In minutes

    private static final int RESET_CODE_LENGTH = 10;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;

    private String token;

    @OneToOne(targetEntity = User.class, fetch = FetchType.EAGER)
    @JoinColumn(nullable = false, name = "userId")
    private User user;

    private Date expirationDate;

The exception I am getting boils down to Cannot delete or update a parent row: a foreign key constraint fails (`heroku_bc5bfe73a752182`.`password_reset_tokens`, CONSTRAINT `FKk3ndxg5xp6v7wd4gjyusp15gq` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`))

I'd like to avoid adding a reference to PasswordResetToken in the parent entity, becaue User shouldn't need to know anything about PasswordResetToken.

解决方案

It is not possible on JPA level without creating bidirectional relation. You need to specify cascade type in User class. User should be owner of the relation and it should provide the information on how to deal with related PasswordResetToken.

But if you can't have bidirectional relation I would recommend you to setup relation directly in schema generation SQL script.

If you create your schema via SQL script and not via JPA autogeneration (I believe all serious projects must follow this pattern) you can add ON DELETE CASCADE constraint there.

It will look somehow like this:

CREATE TABLE password_reset_tokens (
  -- columns declaration here
  user_id INT(11) NOT NULL,
  CONSTRAINT FK_PASSWORD_RESET_TOKEN_USER_ID
  FOREIGN KEY (user_id) REFERENCES users (id)
    ON DELETE CASCADE
);

Here is the documentation on how to use DB migration tools with spring boot. And here is the information on how to generate schema script from hibernate (that will simplify the process of writing your own script).

这篇关于Spring数据JPA:如何启用级联删除而不引用父级中的子级?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆