I have a problem with deleting (by unassign only) roles
which are assigned to user
through association table. Only assignment should be deleted.
I need to have a User
entity with relation ManyToMany to Rolle
entity but this relation (assignment) needs to have additional information like expiriation_date
(because assignment can expire). So, I cannot use automatically created and managed association table by hibernate (@JoinTable - which was working really great when I didn't need an additional column) but now I need to extend the association with an extra column and that's why instead of that @JoinTable I need to create such a association table manualy. Below my model relation which is working when I am adding some roles to user, but not working when I try to delete some role.
USER:
@Entity
@Table(name = "USER")
public class User {
@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "NAME")
private String name;
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<UserRole> userRoleAssignments = new LinkedHashSet<>();
//getters, setters
public List<BrugersystemrolleDB> getRoles() {
return this.userRoleAssignments.stream().
map(roleAssignment -> roleAssignment.getRole()).
collect(Collectors.toList());
}
public void setRoles(List<Role> roles) {
this.userRoleAssignments = roles.stream().
map(role -> useExistingOrNewRoleAssignment(role)).
collect(Collectors.toSet()));
}
private UserRole useExistingOrNewRoleAssignment(Role role) {
Optional<Role> roleAssignmentOpt = getRoleAssignment(role);
if (roleAssignmentOpt.isPresent()) {
return roleAssignmentOpt.get();
} else {
return new UserRole(role, this);
}
}
private Optional<UserRole> getRoleAssignment(Role role) {
return roleAssignments.stream().
filter(roleAssignment ->
roleAssignment.getRole().getId() == role.getId()).findFirst();
}
}
ROLE:
@Entity
@Table(name = "ROLE")
public class Role {
@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(name = "NAME")
private String name;
@OneToMany(mappedBy = "role", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<UserRole> userRoleAssignments = new LinkedHashSet<>();
//getters, setters
}
USER_ROLE:
@Entity
@Table(name = "USER_ROLE")
public class UserRole {
@Id
@Column(name = "ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@ManyToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "USER_ID")
private User user;
@ManyToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "ROLE_ID")
private Role role;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "EXPIRE_DATE", nullable = true)
private Date expireDate;
public UserRole (Role role, User user) {
this.role = role;
this.user = user;
}
//getters, setters
}
用法:
@Stateless
public class UserLogic {
@EJB private UserDao userDao;
@EJB private UserRoleDao userRoledao;
//... just some generic solution for update requests
public User updateUser(User user, UserVo, userVo) {
user.setName(userVo.getName());
assignRollesToUser(user, userVo.getRoles());
return userDao.update(user); // <-- is causing an error when some role is deleted!
}
// this method is responsible for roles management and is causing a problem during update user list of roles, but only when some of them needs to be deleted.
public void assignRollesToUser(User user, List<Integer> roles) {
// 1 step: remove all existing assignments:
user.getRoleAssignments().stream().
forEach(roleAssignment -> {
// 1) solution with userRoleDao is causing a problem with deleted/detached object passed to merge:
userRoleDao.delete(roleAssignment);
// 2) solution with removing role from list gives me an error saying: NULL not allowed for column 'USER_ID' which is true, but why hibernate is not deleting this entry and wants to to set null for user_id which breaks a constraint?
// user.getRoleAssignments().remove(userAssignment);
});
// 2 step: assign new set of roles
List<Role> newRolesToAssign = getRolesFromDB(roles);
user.setRoles(newRolesToAssign )
}
private List<Role> getRolesFromDB(List<Integer> rolles) {
return rolles.stream().
map(userRoleDao::read).
collect(Collectors.toList());
}
}
我可以向用户添加新角色,但无法删除任何角色,当尝试删除时,我正在接收
已删除的实例已传递给合并
或
传递给合并的分离实例
取决于删除方式。我尝试通过dao.delete()
删除角色,或者只删除收集而不删除dao。两种解决方案都不起作用。你能告诉我一些我做错了什么吗?我缺少什么吗?
低于在UserLogic中将forEach更改为:
后出现的错误forEach(roleAssignment -> {
user.getRoleAssignments().remove(userAssignment);
roleAssignment.setUser(null);
roleAssignment.setRole(null);
});
错误:
[Server:server-one] Caused by: java.util.ConcurrentModificationException
[Server:server-one] at java.util.HashMap$HashIterator.nextNode(HashMap.java:1429) [rt.jar:1.8.0_45-internal]
[Server:server-one] at java.util.HashMap$KeyIterator.next(HashMap.java:1453) [rt.jar:1.8.0_45-internal]
[Server:server-one] at org.hibernate.collection.internal.AbstractPersistentCollection$IteratorProxy.next(AbstractPer
sistentCollection.java:789) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
[Server:server-one] at java.util.Iterator.forEachRemaining(Iterator.java:116) [rt.jar:1.8.0_45-internal]
[Server:server-one] at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801) [rt.jar:1
.8.0_45-internal]
[Server:server-one] at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512) [rt.jar:1.8.0_45-intern
al]
[Server:server-one] at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502) [rt.jar:1.8.0_45
-internal]
[Server:server-one] at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151) [rt.jar:1.8.0_4
5-internal]
[Server:server-one] at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174) [rt.jar:1
.8.0_45-internal]
[Server:server-one] at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) [rt.jar:1.8.0_45-intern
al]
[Server:server-one] at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418) [rt.jar:1.8.0_45-internal]
[Server:server-one] at com.myapp.rest.logic.UserLogic.assignRollesToUser(UserLogic.java:280)
为什么我会收到java.util.ConcurrentModificationException
?
答案 0 :(得分:0)
您必须先删除相关实体。因此,如果您有一个实体学生和每个学生都有零个或多个课程,并且学生和班级在学生课程表中多对多加入,您将为每个学生提供一系列课程,并为每个班级提供一组学生。要删除学生,必须先从多对多表中删除他们的课程。因此,如果您有一个方法RemoveStudentClass,它将学生和一个类作为参数,您可以执行类似
的操作 public void RemoveSudent(student deleteStudent)
{
foreach (Class c in deleteSudent.Classes)
{
removeStudentClass(deleteSudent,c);
}
Students.Delete(deleteStudent);
}