简体   繁体   English

Hibernate在entitymanager.flush()上抛出“ org.hibernate.HibernateException:找到相同集合的两个表示形式”

[英]Hibernate throws “org.hibernate.HibernateException: Found two representations of same collection” on entitymanager.flush()

I am currently working on a medium sized Java project with Hibernate and I have come across what seems to be a rare but quite persistent error. 我目前正在使用Hibernate进行一个中等规模的Java项目,遇到了一个罕见的但相当持久的错误。 The situation is as follows: I have a Student entity who has a bidirectional many-to-many relation to an Education entity (implemented as a join table on the database) and an Admin entity who is a subclass of Student. 情况如下:我有一个Student实体,该实体与Education实体具有双向多对多关系(在数据库上实现为联接表),而Admin实体是Student的子类。 My code allows for a Student to be "upgraded" to an Admin by removing the Student from the database, creating a new Admin based on the Student and persisting this Admin. 我的代码允许通过从数据库中删除学生,基于学生创建一个新的管理员并持久保留该管理员来将“学生”“升级”为管理员。 However, whenever this happens, Hibernate throws the following error on EntityManager.flush(): 但是,无论何时发生这种情况,Hibernate都会在EntityManager.flush()上引发以下错误:

org.hibernate.HibernateException: Found two representations of same collection: domain.Student.enrolledEducations

Below you can find the relevant code: 您可以在下面找到相关代码:

Education class 教育班

@Entity
public class Education {

...

@ManyToMany
@JoinColumn(name = "education_id")
private Set<Course> courses = new HashSet<>();

Student class 学生班

@Entity
public class Student {

....

@ManyToMany
@JoinColumn(name = "student_id")
private Set<Education> enrolledEducations = new HashSet<>();

Admin class 管理员班

@Entity
public class Admin extends Student {

...

public Admin(Student student) {
    this.setId(student.getId());
    this.setFirstName(student.getFirstName());
    this.setLastName(student.getLastName());
    this.setEmail(student.getEmail());
    this.setSalt(student.getSalt());
    this.setSuperAdmin(false);
    this.setEnrolledEducations(student.getEnrolledEducations());
    this.setSessions(student.getSessions());
    this.setManagedEducations(new HashSet<Education>());
}

Database methods 数据库方法

public Admin upgrade(Person person) {
    Admin admin;
    if (person instanceof Student){
        removeStudent((Student) person);
        admin = new Admin((Student) person);
    }
    else{
        removePerson(person);
        admin = new Admin(person);

    }
    addAdmin(admin); //exception happens here

    return admin;
}

public void addAdmin(Admin admin) {
    manager.getTransaction().begin();

    if(manager.contains(admin)){
        manager.merge(admin);
    }
    else{
        manager.persist(admin);
    }

    manager.flush(); //exception happens here
    manager.getTransaction().commit();
}

Test method 测试方法

@Test
public void getEducationsForAdmin_and_upgrade_to_admin_work_correctly(){

    educationSetup();

    Admin admin1 = facade.upgrade(student1); //exception happens here
    Admin admin2 = facade.upgrade(student2);

    admin1.addNewEducation(education1);
    admin1.addNewEducation(education2);
    admin2.addNewEducation(education1);

    facade.updateAdmin(admin1);
    facade.updateAdmin(admin2);

    Set<Education> educations1 = new HashSet<>(facade.getEducationsForStudent(admin1));
    Set<Education> educations2 = new HashSet<>(facade.getEducationsForStudent(admin2));

    assertTrue("admin 1 does not have exactly 1 education", educations1.size()==1);
    assertTrue("admin 2 does not have exactly 2 educations", educations2.size()==2);
    assertTrue("admin 1 does not have the IT education",educations1.contains(education1));
    assertTrue("admin 2 does not have the IT education",educations2.contains(education1));
    assertTrue("admin 2 does not have the M education",educations2.contains(education2));
}

It seems that you have a problem that both Admin and Student have the same identifier. 似乎您有一个问题,即Admin和Student具有相同的标识符。

Since the Admin is created by calling the new function, it is not in the persistent state, the code 由于Admin是通过调用新函数创建的,因此它不是处于持久状态,因此代码

manager.contains(admin)

will always return false, so it will always go to the manager.persist statement. 将始终返回false,因此它将始终转到manager.persist语句。

Since Admin is a different object with the same identifier, you will get the exception 由于Admin是具有相同标识符的其他对象,因此您将获得异常

Found two representations of same collection 找到相同集合的两个表示

All you need to do is to add 您需要做的就是添加

manager.delete(person)

in your 在你的

removePerson

function. 功能。 It should solve this problem. 它应该解决这个问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM