Search code examples
javajpaspring-dataspring-data-jpaspring-data-rest

Configure many-to-many relationships in Spring Data REST so deleting one object does not delete the other


I am using the latest Spring Data REST (with JPA and MySQL DB) project. I have two objects that I want to setup a relationship between. But when I delete one of the two, I only want to delete the relationship and the object that received the delete request (not both objects).

What I'm relating:

  • A task
  • A user

where a task can be related to ("owned by") multiple users and a user can be related to ("own") multiple tasks

Task Class:

@ManyToMany
@JoinTable(name = "task_user", joinColumns = @JoinColumn(name = "task_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"))
private Set<User> users;

User class:

@ManyToMany(mappedBy = "users")
private Set<Task> tasks;

The task_user table consists of two columns

  • task_id (the id of the task)
  • user_id (the id of the user)

When I delete a task (via DELETE to /task/{id}), it behaves correctly (the task is deleted from the task table and the relationship is deleted from the task_user table). The issue I have is that when I delete a user, it is deleted from the user table but the relationship still exists in the task_user table.

What I desire:

  • Deleting a task, deletes all corresponding entries in "task_user" and the entry in "task"; does NOT delete entries in "user"
  • Deleting a user, deletes all corresponding entries in "task_user" and the entry in "user"; does not delete entries in "task"

Is it possible to achieve that through configuration? Or do I need to use either foreign keys or custom logic, such as event handlers?


Solution

  • Try this:

    public class User {
       //...
       @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
       private Set<Task> tasks;
       //...
    }
    
    public class Task {
       //...
        @ManyToMany(mappedBy = "tasks")
        private Set<User> users;
       //...
    }
    

    You chose a bidirectional variant of many-to-many so don't forget about 'helper methods' in User class. See documentation: associations many-to-many.

    See my example and tests.