Spring 使用JPA 2.0和@OneToMany删除孤立实体的方法是什么?

Spring 使用JPA 2.0和@OneToMany删除孤立实体的方法是什么?,spring,hibernate,jpa,orphaned-objects,Spring,Hibernate,Jpa,Orphaned Objects,我正在使用JPA2.0、Hibernate4.1.0.Final、Spring3.1.1.RELEASE和Java1.6。我有一个与另一个实体有一对多关系的实体 import javax.persistence.CascadeType; ... @Entity @Table(name = "classroom") public class Classroom implements Serializable { ... @OneToMany(mappedBy = "classro

我正在使用JPA2.0、Hibernate4.1.0.Final、Spring3.1.1.RELEASE和Java1.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对象都将保留。从数据库中删除所有孤立记录时,更新实体的正确/最短方法是什么


谢谢,-Dave

使用
删除孤儿

@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);
    }
}
/**
*组装ClassRoom用户关系。
*@param教室实体。必须是持久的或暂时的。永不为空。
*@param userIds用户标识符的集合。可以是空的。永不为空。
*/
私有void assembleClassroomUsers(教室、集合用户ID){
//确保关系集存在(对于瞬态实例可能为null)
if(教室.getUsers()==null){
setUsers(新HashSet());
}
//创建集合的工作副本
集合ID=新哈希集(userID);
//检查现有关系,并根据需要保留或删除它们
Iterator it=kitch.getUsers().Iterator();
while(it.hasNext()){
整数userId=it.next().getUser().getId();
如果(!ids.remove(userId)){
it.remove();//这将由deleteOlivers=true选择
}
}
//从剩余的标识符集创建新关系
for(整数用户ID:ids){
ClassroomUser ClassroomUser=新建ClassroomUser();
classroomUser.set教室(教室);
//用户不能初始化ClassroomUser关系,否则将休眠
//将获取冲突的指令,其中包含要保留的内容和要删除的内容=>错误。
//使用虚拟瞬态实例可能更安全。。。
用户dummyUser=新用户();
setId(userId);
classroomUser.setUser(dummyUser);
class.getUsers().add(classroomUser);
}
}

这种方法似乎有点复杂。您可以使用自定义的
equals
/
hashCode
和一些
Set
操作方法(例如从番石榴中)创建一些更简单(但可能不会太多)的东西。

谢谢,我试过了,但得到了一个例外,“带有cascade=“all delete orphan”的集合“不再被拥有的实体实例引用:com.myco.fdr.myproject.lms.kitcher.model.kitcher.花名册”这是因为您可能没有按照我的说明操作。您不能替换集合。您能确认即使不更改集合也会收到错误吗?K,按照您的说明操作(清除,然后添加所有),我遇到了一个新的异常--“org.springframework.dao.DataIntegrityViolationException:constraint[null]的重复条目“7745AFA45C304375B6691CAA8C8480FA-STUDENT1”,用于关键的“课堂花名册”\u IDX\u 01;SQL[n/a];约束[null];嵌套异常为org.hibernate.exception.ConstraintViolationException:对于键“教室花名册”IDX_01,重复输入“7745AFA45C304375B6691CAA8C8480FA-STUDENT1”。如果列表中已有用户,则会显示“清除”"不会导致发出任何删除。这可能是Hibernate插入新条目和删除旧条目的顺序。我将使用一个项目中的代码片段更新我的答案,我必须在该项目中实现您尝试实现的内容。非常感谢此代码示例。我想确保我正确实现了它。您不知道是否在任何地方调用“.clear()”?如果是这样,我认为我遵循了逻辑,但是现在孤立记录仍然存在,尽管我已经通过调试验证了调用“it.remove()”方法。
/**
 * 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);
    }
}