简体   繁体   中英

Jpa not inserting the record in the join table for many to many relatioship

I have a Many-to-Many relationship with User and Role JPA entities. When I try to save the entities, both User and Role entities gets persisted in the table, but the junction table is not getting inserted with the records, Where am I going wrong

User Entity

@Entity
@Table(name="users")
@Data
@NoArgsConstructor
@EqualsAndHashCode(exclude = "roles")
@ToString(exclude = "roles")
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    
    private String name;
    private String password;
    private double salary;
    
    public User(String name, String password, double salary) {
        super();
        this.name = name;
        this.password = password;
        this.salary = salary;
    }
    
    
    @ManyToMany(
            mappedBy = "users")
    private Set<Role> roles = new HashSet<>();
    
    
    public void addRole(Role role) {
        this.roles.add(role);
        role.getUsers().add(this);
    }
}

Role Entity

@Entity
@Table(name = "roles")
@Data
@NoArgsConstructor
@EqualsAndHashCode(exclude = "users")
@ToString(exclude = "users")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String roleName;

    public Role(String roleName) {
        super();
        this.roleName = roleName;
    }
    
    @ManyToMany
    @JoinTable(
            name="user_roles",
            joinColumns = @JoinColumn(name="role_id", nullable = false),
            inverseJoinColumns = @JoinColumn(name="user_id", nullable = false)
            )
    private Set<User> users = new HashSet<>();
}

Client class

@EventListener(ApplicationReadyEvent.class)
    public void onApplicationStartup(ApplicationReadyEvent event) {
        
        User kiran = new User("kiran", this.passwordEncoder.encode("welcome"), 4500000);
        
        User vinay = new User("vinay", this.passwordEncoder.encode("welcome"), 4500000);        
        
        Role userRole = new Role("ROLE_USER");
        
        Role adminRole = new Role("ROLE_ADMIN");
        
        
        kiran.addRole(userRole);
        
        vinay.addRole(userRole);
        vinay.addRole(adminRole);
        
        this.userRepository.save(kiran);
        this.userRepository.save(vinay);
        
    }

Where am I going wrong?

You've mapped a bidirectional relationship, but are only setting one side of it in your object model - the wrong side. Should there ever be a discrepancy, the owning side controls the values of foreign keys, and since you have left the owning side empty, they aren't being set. You are responsible to set both sides of relationships and keeping them in synch with what you want in the database.

Since you don't have cascade options set on the relationships, you are also responsible for persisting the roles independently from the Users. Something more like:

public void onApplicationStartup(ApplicationReadyEvent event) {
  // you might want to check to see if these roles already exists and use those instead of creating new ones
  Role userRole = roleRepository.save(new Role("ROLE_USER"));
  Role adminRole = roleRepository.save(new Role("ROLE_ADMIN"));

  User kiran = new User("kiran", this.passwordEncoder.encode("welcome"), 4500000);
  kiran.addRole(userRole);//assumes this adds the user to the role.users as well.
  this.userRepository.save(kiran);

  User vinay = new User("vinay", this.passwordEncoder.encode("welcome"), 4500000);  
  vinay.addRole(userRole);
  vinay.addRole(adminRole);
  this.userRepository.save(vinay);
}

Also, you are using Set in your entities with Lombok using "@EqualsAndHashCode" generation. Don't do that!

Set uses the equals/hashcode logic to determine if two objects are the same to filter out duplicates, while Lombok generates those methods to use what are mutable fields. In the case you have new entities in those sets (ie this usecase), the IDs are null and will change when set from JPA. You are better off keeping Java equals/hashcode logic if you don't know what effects those will have on your application. try using either List in your model and/or not having Lombok generate those method for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM