Let's take a simple and well known example : Users and Groups.
An user can be in many groups, as a group can have many users. But in this case, we want to handle, for example, the date the user entered the group.
So we will have :
The table User :
@Entity
public class User extends com.example.UserItf {
public User() { /* not needed */ }
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
@Override
public Long getId(){
return _id;
}
/* some other fields like name, etc. */
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
@OrderBy("id")
@Override
public List<Group> getGroups(){
return _groups;
}
}
The table UserGroups :
@Entity
public class UserGroups extends com.example.UserGroupsItf {
public UserGroups(){ /* not needed */ }
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
@Override
public Long getId(){
return _id;
}
@ManyToOne
@JoinColumn(name="userid")
@Override
public User getUser() {
return _user;
}
@ManyToOne
@JoinColumn(name="groupid")
@Override
public Group getGroup() {
return _group;
}
@Override
public Date getEntryDate(){
return _date; // only to represent a cross table with extra column
}
}
The table Groups :
@Entity
public class Group extends com.example.GroupItf {
public Group() { /* not needed */ }
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
@Override
public Long getId(){
return _id;
}
/* some other fields like name, etc. */
@OneToMany(mappedBy = "group", fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
@OrderBy("id")
@Override
public List<User> getUsers(){
return _users;
}
}
My current scenario is the same and the problem I am facing is the following : I want to add for a selected user a group, so the steps (correct me if I'm wrong) are :
- Get the desired User (already done)
- Get the desired Group (from a List retrieved from the database)
- Add the Group to the User's List
- Persist the User
This will result in adding / updating an User with a Group, and so creates an entry in UserGroups as well, right ?
Now, I want to remove the Group from the User, so :
- Get the desired User (already done)
- Unselect the Group in the List
- This will remove from the User the Group (
user.getGroups().remove(grp)
) - Persist the User
My problem is that the entry in UserGroups is still existing. I've played around with Cascades, but I do not have the desired behavior : By removing a Group from the User, this also removes the Group in the table (UPDATE : It does not remove the Group, but it doesn't remove the link in UserGroups either).
I just want to delete the relation in the "cross table with extra column" if, from one side or another, I delete the link between User and Group.
I've looked around on Hibernate and StackOverflow, but nothing seems to fit my case. Note that the code for the tables I provided is exactly the code I have in my project.
Is it possible to delete the link only from the Users side for example, and cascade it to delete the UserGroups relation ? Or do I have to manage each entity separately ?
___ EDIT ___
Here is the Hibernate output when adding a Group to an User. Please note that this was an example, so I formatted the output to match the example, but nothing else has been modified.
DEBUG [org.hibernate.SQL]
insert
into
UserGroups
(groupId, entryDate, userId, userGroupsId)
values
(?, ?, ?, ?)
TRACE [descriptor.sql.BasicBinder] binding parameter [1] as [BIGINT] - [1]
TRACE [descriptor.sql.BasicBinder] binding parameter [2] as [DATE] - [xxx] // added to match the example, this is an other field here (boolean)
TRACE [descriptor.sql.BasicBinder] binding parameter [3] as [BIGINT] - [1]
TRACE [descriptor.sql.BasicBinder] binding parameter [4] as [BIGINT] - [7]
And, surprisingely, after enabling the logging output, I see that there is no output for the remove. Is that possible that the EntityManager thinks the entity has not changed ?
The function to persist the user does the following :
_entityManager.getTransaction().begin();
_entityManager.persist( user );
_entityManager.getTransaction().commit();
Also, thanks to @Dragan Bozanovic, it seems that the scenario doesn't fit the problem. Here, nothing changes, nothing moves, so does the UserGroups link.