Reputation: 3024
I have 3 tables Role, User, and UserRole. The table UserRole contains the mapping between user and role along with the two corresponding index columns. I am using hibernate with annotations, and would like to be able to "Revoke" a role from the user, but this is turning out to be somewhat difficult.
In my User Class I have
@ManyToMany(fetch=FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, targetEntity = Role.class)
@IndexColumn(name = "role_index", base = 0)
@NotFound(action=NotFoundAction.IGNORE)
@JoinTable(name = "tblUser_Role", joinColumns={
@JoinColumn(name = "UID")}, inverseJoinColumns={
@JoinColumn(name = "roleid", nullable = false)})
private List<Role> roles = new ArrayList<Role>(0);
In my Role class I have
@ManyToMany(fetch=FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, mappedBy="roles")
private List<User> users = new ArrayList<User>(0);
and the DAO method I am calling to "Revoke" the role(s) is
@Override
public boolean revokeRolesFromUserAccount(User user, List<Role> userRoles) {
if (log.isInfoEnabled()) {
log.info("Roles revoked from the User " + user.getUsername());
}
if (user == null) {
return false;
}
if (userRoles == null) {
return false;
}
Iterator<Role> iter = userRoles.iterator();
List<Role> newroles = new ArrayList<Role>(0);
Role role = null;
while (iter.hasNext()) {
role = (Role) this.sessionFactory.getCurrentSession().load(
Role.class, iter.next().getRoleid());
newroles.add(role);
}
User newUser = null;
newUser = (User) this.sessionFactory.getCurrentSession().load(User.class, user.getUid());
newUser.getRoles().removeAll(newroles);
this.sessionFactory.getCurrentSession().saveOrUpdate(newUser);
return true;
}
for some reason this does not work as expected, when breaking through I noticed the roles were not being initialized I guess due to the LazyLoading, and I tried doing something like Hibernate.initialize(newUser.getRoles())
but this did not change anything. I am still learning the ropes with hibernate and am not sure what I am missing, maybe something very obvious?? Thank you so much for your time and thoughts in advance!
UPDATE: After trying the fixes suggested by Paujo and Matin Kh and doing further debugging I still have not seen any differences in the Roles being loaded in after line newUser = (User) this.sessionFactory.getCurrentSession().load(User.class, user.getUid());
Here is a copy of my tblUser_Role, not sure if this helps. Thanks again!
(Adding roles works just fine)
Upvotes: 0
Views: 510
Reputation: 3024
Finally got this working, mostly by sheer luck, this is what I ended up with in my RoleDaoImpl class.
@Override
@Transactional
public boolean revokeRolesFromUserAccount(User user, List<Role> userRoles) {
if (user == null) {
return false;
}
if (userRoles == null) {
return false;
}
User newUser = null;
newUser = (User) this.sessionFactory.getCurrentSession().load(User.class, user.getUid());
List<Role> newRoleList = newUser.getRoles();
newRoleList.removeAll(userRoles);
if(newUser.getRoles().retainAll(newRoleList)){
if (log.isInfoEnabled()) {
log.info("Roles revoked from the User " + user.getUsername());
}
this.sessionFactory.getCurrentSession().saveOrUpdate(newUser);
return true;
}else{
return false;
}
Hope this can be of some use to others in the future!
Thanks again for everyone's help!
Upvotes: 0
Reputation: 5178
I'm having the exact situation here. Your question has a very simple solution.
For one of your classes use EAGER
, and for the other one use LAZY
. Try this:
Role:
@ManyToMany(fetch=FetchType.EAGER, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, mappedBy="roles")
private List<User> users = new ArrayList<User>(0);
User:
@ManyToMany(fetch=FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, targetEntity = Role.class)
@IndexColumn(name = "role_index", base = 0)
@NotFound(action=NotFoundAction.IGNORE)
@JoinTable(name = "tblUser_Role", joinColumns={
@JoinColumn(name = "UID")}, inverseJoinColumns={
@JoinColumn(name = "roleid", nullable = false)})
private List<Role> roles = new ArrayList<Role>(0);
Upvotes: 1
Reputation: 2479
I think your approach should be different.
UserRole should have a role name.
Your User should have a list of UserRole items or just one UserRole but with a hierarchy of UserRole. But as you have a list that is ok.
So basically you have references in User to UserRole so there is no need to have references to User in UserRole.
That way your table becomes very simple and you dont need any joins to do it and you can then just select UserRole by name.
After that you should be able to remove the reference from the list of UserRole in User and merge the User.
Upvotes: 0