Spring data JPA: how to enable cascading delete without a reference to the child in the parent?

Tags: , , , ,

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

The user entity:

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

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

    private String firstName;

    private String lastName;

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

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

    private String salt;

    private boolean enabled;

    @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?

@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;

    @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 a 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 cannot have a 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,
  FOREIGN KEY (user_id) REFERENCES users (id)

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).

Source: stackoverflow