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.