Java hibernate insert to a collection导致删除,然后再次插入集合中的所有项

Java hibernate insert to a collection导致删除,然后再次插入集合中的所有项,java,hibernate,orm,jpa,Java,Hibernate,Orm,Jpa,我有很多可能的关系,包括团队和员工。每当我将员工插入CohortGroup时,hibernate都会从resolution表中删除该组,并再次插入所有成员以及新成员。为什么不加一个新的呢 组中的注释: @ManyToMany(cascade = { PERSIST, MERGE, REFRESH }) @JoinTable(name="MYSITE_RES_COHORT_GROUP_STAFF", joinColumns={@JoinColumn(name="COHORT_GROUPID")},

我有很多可能的关系,包括团队和员工。每当我将员工插入CohortGroup时,hibernate都会从resolution表中删除该组,并再次插入所有成员以及新成员。为什么不加一个新的呢

组中的注释:

@ManyToMany(cascade = { PERSIST, MERGE, REFRESH })
@JoinTable(name="MYSITE_RES_COHORT_GROUP_STAFF",
joinColumns={@JoinColumn(name="COHORT_GROUPID")},
inverseJoinColumns={@JoinColumn(name="USERID")})
public List<Employee> getMembers(){
  return members;
}
下面是日志中报告的sql

delete from swas.MYSITE_RES_COHORT_GROUP_STAFF where COHORT_GROUPID=?
insert into swas.MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?)
insert into swas.MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?)
insert into swas.MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?)
insert into swas.MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?)
insert into swas.MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?)
insert into swas.MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?)
这确实效率低下,并导致了一些问题。如果有人要求在团队中增加一名员工,那么有些人会被忽略

equals和hashCode之类的接缝可能是原因之一。下面是这些方法的实现。有危险信号吗

同伙群

    @Override
public int hashCode() {
    final int prime = 31;
    int result = getName().hashCode();
    result = prime * result + ((emp == null) ? 0 : emp.hashCode());
    return result;
}
@Override
public boolean equals(Object obj) {
    if (this == obj) {return true;}
    if (!(obj instanceof CohortGroup)) {return false;}
    CohortGroup other = (CohortGroup) obj;
    if(!getName().equals(other.getName())){return false;}
    if (emp == null && other.getOwner() != null) {
        return false;
    } else if (!emp.equals(other.getOwner())) {
        return false;
    }
    return true;
}
@OneToMany(mappedBy="group")
public List<CohortGroupMember> getMembers(){
    return members;
}
public void setMembers(List<CohortGroupMember> emps){
    members = emps;
}
雇员

       @Override
public boolean equals(Object obj) {
    if (this == obj) {return true;}
    if (obj == null) {return false;}
    if (!(obj instanceof Employee)) {return false;}
    Employee other = (Employee) obj;
    if (EMPLID == null && other.getEMPLID() != null) {
        return false;
    } else if (!EMPLID.equals(other.getEMPLID())) {
        return false;
    }
    return true;
}

   @Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((EMPLID == null) ? 0 : EMPLID.hashCode());
    return result;
}
我已向CohortGroup添加了一个addMember方法,该方法将添加到关系的双方:

    public void addMember(Employee emp){
    this.getMembers().add(emp);
    emp.getMemberGroups().add(this);

}

继续感谢所有的帮助。

您必须在您的
同伙组
员工
实体上定义
hashCode()
equals()
。这可以由IDE自动完成,它可以在主键上(有时不是一个好主意)或者在业务键上(最好)


阅读。

我高度怀疑您没有正确重写
equals
hashCode
。错误地覆盖它们可能会导致您正在经历的行为(因为散列键在映射中用作键)。仔细检查您对
equals
hashCode
所做的操作

使用带有良好
等于
hashCode
注释实体,此代码(逻辑等效):

在我的机器上生成以下输出:

08:10:32.426 [main] DEBUG o.h.e.d.AbstractFlushingEventListener - processing flush-time cascades 08:10:32.431 [main] DEBUG o.h.e.d.AbstractFlushingEventListener - dirty checking collections 08:10:32.432 [main] DEBUG org.hibernate.engine.CollectionEntry - Collection dirty: [com.stackoverflow.q2649145.CohortGroup.members#1] 08:10:32.432 [main] DEBUG org.hibernate.engine.CollectionEntry - Collection dirty: [com.stackoverflow.q2649145.Employee.memberGroup#1] 08:10:32.443 [main] DEBUG org.hibernate.engine.Collections - Collection found: [com.stackoverflow.q2649145.CohortGroup.members#1], was: [com.stackoverflow.q2649145.CohortGroup.members#1] (initialized) 08:10:32.448 [main] DEBUG org.hibernate.engine.Collections - Collection found: [com.stackoverflow.q2649145.Employee.memberGroup#1], was: [com.stackoverflow.q2649145.Employee.memberGroup#1] (uninitialized) 08:10:32.460 [main] DEBUG o.h.e.d.AbstractFlushingEventListener - Flushed: 0 insertions, 0 updates, 0 deletions to 2 objects 08:10:32.461 [main] DEBUG o.h.e.d.AbstractFlushingEventListener - Flushed: 0 (re)creations, 2 updates, 0 removals to 2 collections 08:10:32.463 [main] DEBUG org.hibernate.pretty.Printer - listing entities: 08:10:32.473 [main] DEBUG org.hibernate.pretty.Printer - com.stackoverflow.q2649145.CohortGroup{id=1, members=[com.stackoverflow.q2649145.Employee#1]} 08:10:32.474 [main] DEBUG org.hibernate.pretty.Printer - com.stackoverflow.q2649145.Employee{id=1, memberGroup=} 08:10:32.474 [main] DEBUG o.h.p.c.AbstractCollectionPersister - Inserting collection: [com.stackoverflow.q2649145.CohortGroup.members#1] 08:10:32.480 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0) 08:10:32.491 [main] DEBUG org.hibernate.SQL - insert into MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?) Hibernate: insert into MYSITE_RES_COHORT_GROUP_STAFF (COHORT_GROUPID, USERID) values (?, ?) 08:10:32.496 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 1 08:10:32.497 [main] TRACE org.hibernate.type.LongType - binding '1' to parameter: 2 08:10:32.499 [main] DEBUG o.h.p.c.AbstractCollectionPersister - done inserting collection: 1 rows inserted
正如其他人所建议的,这可能是
hashcode
equals
的问题

具体来说:Hibernate代理会导致您在
equals
方法中使用的
instaceof
出现问题。这意味着坏消息

看看这个:

我现在有一些插页按我期望的方式运行。多亏了Pascal和z5h,我学到了很多。我相信我已经正确地实现了hashCode和equals。但这并没有解决我的问题。相反,我实现了一个中间实体

下面值得一提的是我的Employee、CoortGroup和now CoortGroupMemeber类中的映射

雇员:

@OneToMany(mappedBy="member")
public List<CohortGroupMember> getMemberGroups(){
   return memberGroups;
}
public void setMemberGroups(List<CohortGroupMember> grps){
   memberGroups = grps;
}
同伙群

    @Override
public int hashCode() {
    final int prime = 31;
    int result = getName().hashCode();
    result = prime * result + ((emp == null) ? 0 : emp.hashCode());
    return result;
}
@Override
public boolean equals(Object obj) {
    if (this == obj) {return true;}
    if (!(obj instanceof CohortGroup)) {return false;}
    CohortGroup other = (CohortGroup) obj;
    if(!getName().equals(other.getName())){return false;}
    if (emp == null && other.getOwner() != null) {
        return false;
    } else if (!emp.equals(other.getOwner())) {
        return false;
    }
    return true;
}
@OneToMany(mappedBy="group")
public List<CohortGroupMember> getMembers(){
    return members;
}
public void setMembers(List<CohortGroupMember> emps){
    members = emps;
}
@OneToMany(mappedBy=“group”)
公共列表getMembers(){
返回成员;
}
公共成员(列出EMP){
成员=环境管理计划;
}

我为这本书所遵循的是Java Persistence with Hibernate第7.2.3章

我也有同样的问题,经过一些尝试和错误发现,如果我使用集合而不是列表作为集合,则不会发生删除。令人恼火的是,考虑到我使用的是JSF,UI组件只会在列表上迭代。但是它就在这里。

在持久性上下文中加载对象,如果存在则调用merge,如果不存在则调用save

Employee emp = new Employee();
//set emp attribute and members.
Session session = ...
Transaction transaction = ...
Employee db = (Employee) session.get(Employee .class,emp.getId());
if(db != null)  session.merge(emp);
else  session.save(emp);
/*session.saveOrUpdate(emp); This will delete the join table and reinsert entry  
again*/
transaction.commit();
session.close();

我也有同样的问题。我从列表改为集合。这对我有用

@ManyToMany(cascade = { PERSIST, MERGE, REFRESH })
@JoinTable(name="MYSITE_RES_COHORT_GROUP_STAFF",
joinColumns={@JoinColumn(name="COHORT_GROUPID")},
inverseJoinColumns={@JoinColumn(name="USERID")})
public Set<Employee> getMembers(){
  return members;
}

@ManyToMany(mappedBy="members",cascade = { PERSIST, MERGE, REFRESH } )
public Set<CohortGroup> getMemberGroups(){
  return memberGroups;
}
@ManyToMany(级联={PERSIST,MERGE,REFRESH})
@JoinTable(name=“MYSITE\u RES\u court\u GROUP\u STAFF”,
joinColumns={@JoinColumn(name=“court_GROUPID”)},
inverseJoinColumns={@JoinColumn(name=“USERID”)}
公共集getMembers(){
返回成员;
}
@ManyToMany(mappedBy=“members”,cascade={PERSIST,MERGE,REFRESH})
公共集合getMemberGroups(){
返回成员组;
}

是的,我也有同样的行为。我刚刚学会了如何使用它:-)当你在一个外键上设置一个列表/设置时,就会发生这种情况。你如何使用它?放慢用户界面的速度,以防止其发生。我有一个ajax应用程序,它可以以用户可以点击的速度拍摄这些请求。这会导致插入件上出现一些间歇性的错误。我或多或少也有相同的问题。。。要有信心!我将再次检查散列码和等于。它们已经实现了,我刚刚让Eclipse为我创建了它们。如果这不起作用,我会开始写下你的其他建议。我将发布我的结果以促进繁荣。我非常确定我已经正确地实现了hashcode和equals,但行为仍然存在。第一次将组和员工添加到其中时,不会删除。如果团队中已经有超过一名员工,就会发生这种情况。不确定您的测试是否向已经有员工的组中添加了员工。Pascal,谢谢您的帮助。如果我想显示hashcode和equals方法,我会在哪里发布呢?作为此问题的答案,还是编辑上面的问题?@标记最好编辑您的问题。使用答案作为答案。我在equals和hashCode方法中放置了一个system.out。执行插入时,不会打印任何内容。这是否意味着我找错了问题的位置?感谢文章的链接,它有助于修改equals方法来比较类getName(this.getClass().getName().equals(other.getClass().getName())绕过这个问题,或者暗示要更改以使用访问者模式检索这些列表?不,更改该方法不会起作用。因为代理类有有趣的名称。可以做的一件事是添加一个方法,如so
public Class getthis Class(){return this.getClass();}
。当您在代理上调用
getClass
时,您将获得代理的类。当您调用
getThisClass
时,它将委托给您的“real”类。与visitor相比,这是一种黑客行为。在调用该方法之前,我是否需要添加一些检查以确保该方法存在?equals执行instanceof的原因是确保强制转换传入对象是安全的。因此,我要么不理解从equals方法调用getThisClass时该如何工作,要么visitor选项是s直到成为最好的研究对象。我使用的对象不是任何东西的子类。它们确实实现了一些接口,但它们没有扩展任何东西。如果我理解我正在阅读的内容,那么这可能不是原因
@OneToMany(mappedBy="group")
public List<CohortGroupMember> getMembers(){
    return members;
}
public void setMembers(List<CohortGroupMember> emps){
    members = emps;
}
Employee emp = new Employee();
//set emp attribute and members.
Session session = ...
Transaction transaction = ...
Employee db = (Employee) session.get(Employee .class,emp.getId());
if(db != null)  session.merge(emp);
else  session.save(emp);
/*session.saveOrUpdate(emp); This will delete the join table and reinsert entry  
again*/
transaction.commit();
session.close();
@ManyToMany(cascade = { PERSIST, MERGE, REFRESH })
@JoinTable(name="MYSITE_RES_COHORT_GROUP_STAFF",
joinColumns={@JoinColumn(name="COHORT_GROUPID")},
inverseJoinColumns={@JoinColumn(name="USERID")})
public Set<Employee> getMembers(){
  return members;
}

@ManyToMany(mappedBy="members",cascade = { PERSIST, MERGE, REFRESH } )
public Set<CohortGroup> getMemberGroups(){
  return memberGroups;
}