hibernate插入到集合会导致删除,然后再次插入集合中的所有项目

Mar*_*ark 8 java orm hibernate jpa

我和CohortGroup和员工有很多关系.每当我将一个Employee插入CohortGroup时,hibernate都会从分辨率表中删除该组,并再次插入所有成员,再加上新成员.为什么不添加新的?

集团中的注释:

@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;
}
Run Code Online (Sandbox Code Playgroud)

员工的另一面

@ManyToMany(mappedBy="members",cascade = { PERSIST, MERGE, REFRESH } )
public List<CohortGroup> getMemberGroups(){
  return memberGroups;
}
Run Code Online (Sandbox Code Playgroud)

代码片段

Employee emp = edao.findByID(cohortId);
CohortGroup group = cgdao.findByID(Long.decode(groupId));
group.getMembers().add(emp);
cgdao.persist(group);
Run Code Online (Sandbox Code Playgroud)

下面是日志中报告的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 (?, ?)
Run Code Online (Sandbox Code Playgroud)

这种缝合效率非常低,并且会导致一些问题.如果要求将一名员工添加到该组中,则会有一些人过来写入.

像equals和hashCode这样的接缝可能就是这个原因.以下是这些方法的实现.有没有红旗?

CohortGroup

    @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;
}
Run Code Online (Sandbox Code Playgroud)

雇员

       @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;
}
Run Code Online (Sandbox Code Playgroud)

我在CohortGroup中添加了addMember方法,该方法添加到关系的两端:

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

}
Run Code Online (Sandbox Code Playgroud)

继续感谢所有有帮助的人.

Pas*_*ent 7

我高度怀疑,你没有覆盖equalshashCode正确.错误地覆盖它们会导致您遇到的行为(因为散列键用作映射中的键).仔细检查你做了什么equalshashCode.

使用注明实体具有良好的equalshashCode,这个代码(逻辑上等同):

Session session = HibernateUtil.beginTransaction();
Employee emp = (Employee) session.load(Employee.class, 1L);
CohortGroup group = (CohortGroup) session.load(CohortGroup.class, 1L);
group.getMembers().add(emp);
emp.getMemberGroup().add(group); // set the other side too!!
session.saveOrUpdate(group);
HibernateUtil.commitTransaction();
Run Code Online (Sandbox Code Playgroud)

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

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

插入前没有删除!

顺便说一句,请注意您应该设置链接上 具有双向协会工作时边,像我一样对集团对雇员.

或者在您的类上添加防御性链接管理方法,例如CohortGroup:

public void addToMembers(Employee emp) {
    this.getMembers().add(emp);
    emp.getMemberGroup().add(this);
}

public void removeFromMembers(Employee emp) {
    this.getMembers().remove(emp);
    emp.getMemberGroup().remove(this);
}
Run Code Online (Sandbox Code Playgroud)


小智 5

我有同样的问题,并且发现一些试验和错误,如果我使用Set而不是List作为我的集合,则不会发生删除.令人恼火,因为我正在使用JSF和UI组件只会迭代列表.但它确实如此.

  • 这是问题的根源.有关详细信息,请参阅http://assarconsulting.blogspot.com/2009/08/why-hibernate-does-delete-all-then-re.html. (4认同)

Mar*_*ark 0

我的插入内容现在按照我期望的方式运行。感谢 Pascal 和 z5h,我学到了很多东西。我相信我已经正确实现了 hashCode 和 equals 。但这从来没有解决我的问题。相反,我实现了一个中间实体。

下面的价值是我的 Employee、CohortGroup 和现在的 CohortGroupMemeber 类中的映射。

员工:

@OneToMany(mappedBy="member")
public List<CohortGroupMember> getMemberGroups(){
   return memberGroups;
}
public void setMemberGroups(List<CohortGroupMember> grps){
   memberGroups = grps;
}
Run Code Online (Sandbox Code Playgroud)

群组成员

@ManyToOne
@JoinColumn(name="USERID")
public Employee getMember(){
    return emp;
}
public void setMember(Employee e){
    emp = e;
}
@ManyToOne
@JoinColumn(name="COHORT_GROUPID")
public CohortGroup getGroup(){
    return group;
}
public void setGroup(CohortGroup cg){
    group   = cg;
}
Run Code Online (Sandbox Code Playgroud)

队列组

@OneToMany(mappedBy="group")
public List<CohortGroupMember> getMembers(){
    return members;
}
public void setMembers(List<CohortGroupMember> emps){
    members = emps;
}
Run Code Online (Sandbox Code Playgroud)

我为此关注的书是 Java Persistence with Hibernate 第 7.2.3 章