Search code examples
javamysqlspring-bootapimany-to-many

many-to-many relationship springboot mysql


i have 2 models User and roles , its a many to many relation ship. i need to add a user and give him a specific role already present in my data base. ------User------

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString

@Entity
@Table(name = "user")
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="user_Id")
    private int userId;
    @Column(name="name")
    private String name;
    @Column(name="lastname")
    private String lastname;
    @Column(name="email")
    private String email;
    @Column(name="password")
    private String password;
    @Column(name="isActive")
    private boolean isActive;
    @Column(name="lastActive")
    private String lastActive;
    @Column(name="createdDate")
    private String createdDate;
    @Column(name="isBlocked")
    private boolean isBlocked;
    
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "institution_id", nullable = false)
    @JsonIgnoreProperties(value = {"user"})
    private Institution institution;
    
    @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.DETACH,CascadeType.MERGE,CascadeType.REFRESH})
    @JoinTable(name = "user_has_role",
            joinColumns = {
                    @JoinColumn(name = "user_id", referencedColumnName = "user_id",
                            nullable = false, updatable = true)},
            inverseJoinColumns = {
                    @JoinColumn(name = "role_id", referencedColumnName = "role_id",
                            nullable = false, updatable = true)})
    @JsonIgnoreProperties(value = {"users"})
    private Set<Role> roles = new HashSet<>();

}

--------Roles--------

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString

@Entity
@Table(name = "role")
public class Role {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="role_Id")
    private int roleId;
    @Column(name="name")
    private String name;
    @Column(name="description")
    private String description;
    @ManyToMany(mappedBy = "roles", fetch = FetchType.LAZY)
    @JsonIgnoreProperties(value = {"roles"})
    private Set<User> users = new HashSet<>();

}

and the application's controller

@PostMapping("/addUser")
    public String addUser(@RequestBody User user) {
        userrepository.save(user);
        return "user saved with name: " + user.getName();
    }

and this is the json body i send with the api request.

{
        "userId" : 7,
        "name": "test",
        "lastname": "testlast",
        "email": "[email protected]",
        "password": "test123",
        "lastActive": "04/05/21",
        "createdDate": "02/04/20",
        "institution": {
            "institutionId": 4
            },
       "roles": [
            {
                "roleId": 2
            }
        ],  
        "active": false,
        "blocked": true
    }

everything worls just fine to my user-has-role table a record is added with the userId = 7 and roleId=2 but the problem is that the table role is getting updated and the fields name and description are getting erased and replaced by null values... any ideas please


Solution

  • You have added CascadeType.PERSIST to User and Role @ManyToMany join.
    When the User entity is persisted to the EntityManager, it will also persist the Role entity. As you are passing the primary key in the request payload for Role it will create/update the Role table.

    You need to remove the CascadeType.PERSIST from joining and it will work as expected.

    @ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH })
        @JoinTable(name = "user_has_role",
                joinColumns = {
                        @JoinColumn(name = "user_id", referencedColumnName = "user_id",
                                nullable = false, updatable = true)},
                inverseJoinColumns = {
                        @JoinColumn(name = "role_id", referencedColumnName = "role_id",
                                nullable = false, updatable = true)})
        @JsonIgnoreProperties(value = {"users"})
        private Set<Role> roles = new HashSet<>();