I'm using JPA 2.0, Hibernate 4.1.0.Final, Spring 3.1.1.RELEASE, and Java 1.6. I have this entity with a one-to-many relationship to another entity …
import javax.persistence.CascadeType;
...
@Entity
@Table(name = "classroom")
public class Classroom implements Serializable
{
...
@OneToMany(mappedBy = "classroom", cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
private Set<ClassroomUser> roster;
However, when I update my entity with a different set of ClassroomUser objects
classroom.setRoster(newRoster);
and save the entity, all the previous ClassroomUser objects remain. What is the proper/shortest way to update my entity while removing all the orphan records from the database?
Thanks, - Dave
Use orphanRemoval
:
@OneToMany(mappedBy="classroom", cascade={CascadeType.ALL}, orphanRemoval=true)
Whenever an entry is removed from the persistent set, it will get deleted. And this means you need to work with the persistent set. I.e. you are not allowed to replace the set, instead you should do:
classroom.getRoster().clear();
classroom.getRoster().addAll(newRoster);
EXAMPLE how to synchronize persistent set with a user required set:
/**
* Assemble ClassroomUser relations.
* @param classroom Classroom entity. Must be attached persistent or transient. Never null.
* @param userIds Collection of user identifiers. Can be empty. Never null.
*/
private void assembleClassroomUsers(Classroom classroom, Collection<Integer> userIds) {
// Make sure relation set exists (might be null for transient instance)
if (classroom.getUsers() == null) {
classroom.setUsers(new HashSet<ClassroomUser>());
}
// Create working copy of the collection
Collection<Integer> ids = new HashSet<Integer>(userIds);
// Check existing relations and retain or remove them as required
Iterator<ClassroomUser> it = classroom.getUsers().iterator();
while (it.hasNext()) {
Integer userId = it.next().getUser().getId();
if (!ids.remove(userId)) {
it.remove(); // This will be picked by the deleteOrphans=true
}
}
// Create new relations from the remaining set of identifiers
for (Integer userId : ids) {
ClassroomUser classroomUser = new ClassroomUser();
classroomUser.setClassroom(classroom);
// User must not have ClassroomUser relations initialized, otherwise Hibernate
// will get conflicting instructions what to persist and what to drop => error.
// It might be safer to use dummy transient instance...
User dummyUser = new User();
dummyUser.setId(userId);
classroomUser.setUser(dummyUser);
classroom.getUsers().add(classroomUser);
}
}
This approach might seem a little bit complex. You might be able to create something simpler (but probably not too much) with custom equals
/hashCode
and some Set<E>
manipulation methods (e.g. from Guava).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With