Какой обходной путь для удаления потерянных сущностей с использованием JPA 2.0 и @OneToMany?
Я использую JPA 2.0, Hibernate 4.1.0.Final, Spring 3.1.1.RELEASE и Java 1.6. У меня есть эта сущность с отношением один ко многим с другой сущностью...
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;
Однако, когда я обновляю свою сущность другим набором объектов ClassroomUser
classroom.setRoster(newRoster);
и сохранить объект, все предыдущие объекты ClassroomUser остаются. Как правильно / кратчайшим образом обновить мою сущность при удалении всех бесхозных записей из базы данных?
Спасибо, Дэйв
1 ответ
Использование orphanRemoval
:
@OneToMany(mappedBy="classroom", cascade={CascadeType.ALL}, orphanRemoval=true)
Всякий раз, когда запись удаляется из постоянного набора, она будет удалена. А это значит, что вам нужно работать с постоянным набором. Т.е. вы не можете заменить набор, вместо этого вы должны сделать:
classroom.getRoster().clear();
classroom.getRoster().addAll(newRoster);
ПРИМЕР: как синхронизировать постоянный набор с пользовательским набором:
/**
* 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);
}
}
Этот подход может показаться немного сложным. Вы можете создать что-то более простое (но, вероятно, не слишком) с помощью пользовательских equals
/hashCode
и немного Set<E>
методы манипуляции (например, из гуавы).