I have a user class and role class and user role class. Now every time i am trying to add a new user with a set of role which is already existing it throws a Unique error which is correct. But ideally it should not try to save the new role if it already exists. Below i am adding all my tables and save method.
@Table(name = "t_user")
@Data
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "mobile_number")
private String mobileNumber;
@Column(name = "email")
private String email;
@Column(name = "first_name")
private String firstName;
@Size(max = 100)
@NotBlank(message = "Last name can not be empty")
@Column(name = "last_name")
private String lastName;
@Column(name = "is_archived")
private Boolean isArchived = false;
@Column(name = "qualification")
private String qualification;
@JsonIgnore
@Column(name="password")
private String password;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(name = "t_user_role", joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {
@JoinColumn(name = "role_id", referencedColumnName = "id")})
private Set<Role> roles = new HashSet<>();
}
@Data
@Table(name = "m_role")
@Entity
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name="name")
private String name;
}
@Data
@Table(name = "t_user_role")
@Entity
public class UserRole {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
@ManyToOne
@JoinColumn(name = "role_id")
private Role role;
}
method where i am saving the user:
User newUser = new User();
newUser.setFirstName(user.getFirstName());
newUser.setLastName(user.getLastName());
newUser.setEmail(user.getEmail());
newUser.setMobileNumber(user.getPassword());
newUser.setPassword(bcryptEncoder.encode(user.getPassword()));
newUser.setRoles(user.getRoles());
return userRepository.save(newUser);
}
and below is the post request format to create the user:
{
"firstName":"first",
"lastName":"name",
"email":"email@gmail.com",
"mobileNumber":"1110122223",
"password":"1234567890",
"roles":[{
"name":"ADMIN"
}]
}
I do not want to insert the role if present which should be ideal. But this is the standard way i find while implementing spring security with roles
Your request is missing id
of the role. As id
is not present. Spring try to add a new role in role
table.
{
"firstName":"first",
"lastName":"name",
"email":"email@gmail.com",
"mobileNumber":"1110122223",
"password":"1234567890",
"roles":[{
"id" : "" // ID must be present here.
"name":"ADMIN"
}]
}
Or from the role -> name
, you can fetch Role
entity/obj from the role table and set it in User
object.
[Update 2]:
@ManyToMany(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
@ToString.Exclude
private Set<Role> roles = new HashSet<>();
You need to change the cascade type from 'ALL' to 'DETACH'. See: ALL
means if you save USER, ROLE will also get saved, if you delete USER, role should also get delete. This is not what we want. You only need to use 'ROLE', not manipulate the 'ROLE' tables record in any way.
On behalf of what I understand, your requirements are:
In your case, I would suggest let Spring take care of the User->Roles relationship as follows:
public class User {
... all fields
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@ToString.Exclude
private Set<Role> roles = new HashSet<>();
}
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
}
In Role repository, you would want a method: Optional<Role> findByName(String Name);
In between the layers (preferably in the service layer), try this:
public Map<String, Object> addUser(User user) {
// perform validations
user.getRoles().forEach(role -> {
Role existing = roleRepository.findByName(role.getName())
.orElse(new Role(role.getName())); // using optional to create new role with name passed in from the client
if (existing.getId() != null) user.setRole(existing); // UPDATE: NOT IDEAL
});
... other tasks
userRepository.save(user); // this all saves the correct role
return yourResponseMap;
}
Other notes:
org.hibernate.PersistentObjectException: detached entity passed to persist
occurs when you're trying to save the role passed in from client directly without loading it on your application (see the service layer method for 'add user').
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.