Home > Enterprise >  Springboot @ManyToMany throws detached entity passed
Springboot @ManyToMany throws detached entity passed

Time:06-29

In my SpringBoot application I created two entities, users and privileges. I also would create a table that associates the id of the users with the id of the privileges they have. Here my User entity:

@Entity
@Table(name = "user", catalog = "users")
public class User implements Serializable
{

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false, unique = true)
private String username;

@Column(nullable = false, unique = true)
private String mail;

private String password;

@ManyToMany(cascade = {
    CascadeType.PERSIST,
    CascadeType.MERGE})
@JoinTable(name = "user_to_privileges",
        joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)},
        inverseJoinColumns = {@JoinColumn(name = "privilege_id",  referencedColumnName = "id", nullable = false)})
private Set<Privilege> privileges= new HashSet<>();

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "organization_id", nullable = false)
private Organization organization;

//

public User() {
    super();
}

public User(String username, String password, String mail, Set<Privilege> privileges, Organization organization) {
    super();
    this.username=username;
    this.password=password;
    this.privileges=privileges;
    this.organization=organization;
    this.mail=mail;        
}
//
public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getUsername() {
    return username;
}

public void addPrivileges(Privilege priv)
{
  priv.addUser(this);
  this.privileges.add(priv);
 }

public void setUsername(String username) {
    this.username = username;
}

 public String getMail() {
    return mail;
}

public void setMail(String mail) {
    this.mail = mail;
}

public String getPassword() {
    return password;
}

public void setPassword(String password) {
    this.password = password;
}

public Set<Privilege> getPrivileges() {
    return privileges;
}

public void setPrivileges(Set<Privilege> privileges) {
    this.privileges = privileges;
}

public Organization getOrganization() {
    return organization;
}

public void setOrganization(Organization organization) {
    this.organization = organization;
}

//

@Override
public String toString() {
    final StringBuilder builder = new StringBuilder();
    builder.append("User [id=").append(id).append(", username=").append(username).append(", password=").append(password).append(", privileges=").append(privileges).append(", organization=").append(organization).append("]");
    return builder.toString();
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = (prime * result)   ((id == null) ? 0 : id.hashCode());
    result = (prime * result)   ((organization == null) ? 0 : organization.hashCode());
    result = (prime * result)   ((password == null) ? 0 : password.hashCode());
    result = (prime * result)   ((privileges == null) ? 0 : privileges.hashCode());
    result = (prime * result)   ((username == null) ? 0 : username.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final User other = (User) obj;
    if (id == null) {
        if (other.id != null) {
            return false;
        }
    } else if (!id.equals(other.id)) {
        return false;
    }
    if (organization == null) {
        if (other.organization != null) {
            return false;
        }
    } else if (!organization.equals(other.organization)) {
        return false;
    }
    if (password == null) {
        if (other.password != null) {
            return false;
        }
    } else if (!password.equals(other.password)) {
        return false;
    }
    if (privileges == null) {
        if (other.privileges != null) {
            return false;
        }
    } else if (!privileges.equals(other.privileges)) {
        return false;
    }
    if (username == null) {
        if (other.username != null) {
            return false;
        }
    } else if (!username.equals(other.username)) {
        return false;
    }
    return true;
}
    }

and Privilege entity:

@Entity
@Table(name = "privilege", catalog = "users")
 public class Privilege implements Serializable
{

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(nullable = false, unique = true)
private String name;

@ManyToMany(mappedBy= "privileges")    
private Set<User> users = new HashSet<>();


public Privilege() {
    super();
}

public Privilege(String name) {
    super();
    this.name = name;
}

public void addUser(User user)
{
  this.users.add(user);
}

public Long getId() {
    return id;
}

public void setId(Long id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public Set <User> getUsers() {
    return users;
}

public void getUsers(final Set<User> users) {
    this.users = users;
}
//

@Override
public String toString() {
    final StringBuilder builder = new StringBuilder();
    builder.append("Privilege [id=").append(id).append(", name=").append(name).append("]");
    return builder.toString();
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = (prime * result)   ((id == null) ? 0 : id.hashCode());
    result = (prime * result)   ((name == null) ? 0 : name.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final Privilege other = (Privilege) obj;
    if (id == null) {
        if (other.id != null) {
            return false;
        }
    } else if (!id.equals(other.id)) {
        return false;
    }
    if (name == null) {
        if (other.name != null) {
            return false;
        }
    } else if (!name.equals(other.name)) {
        return false;
    }
    return true;
}
}

Creating a user like:

        User user =new User();
        user.setUsername("username");
        user.setPassword(encodePassword("test"));
        user.setMail(mail);      
        user.setOrganization(org);
        user.setPrivileges(adminPriv);
        userRep.save(user);

throws an

org.hibernate.PersistentObjectException: detached entity passed to persist: it.unict.spring.application.persistence.model.user.Privilege

Organization and Privilege are correctly persisted into the database, but due to setPrivileges (or analogously the parameterized constructor of User) this error is thrown. I guess that there is something wrong with the definitions of entities but I cannot get rid. Any aidea?

CodePudding user response:

As you have a @ManyToMany relationship you need to reference both objects each other.

User user = new User();
user.addPrivileges(admin);

...
public void addPrivileges(Privilege priv){
   priv.addUser(this);
   this.privileges.add(priv);
}

Take a look in depth for an example of many to many relationship using JPA. Link: https://vladmihalcea.com/the-best-way-to-use-the-manytomany-annotation-with-jpa-and-hibernate/

CodePudding user response:

It seems working using cascade = {CascadeType.MERGE, CascadeType.REFRESH}, but I have absolutely no idea why. Any hint would be very appraciated.

  • Related