hibernate插入到集合会导致删除,然后再次插入集合中的所有项目
我和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 getMembers(){ return members; }
员工的另一面
@ManyToMany(mappedBy="members",cascade = { PERSIST, MERGE, REFRESH } ) public List getMemberGroups(){ return memberGroups; }
代码片段
Employee emp = edao.findByID(cohortId); CohortGroup group = cgdao.findByID(Long.decode(groupId)); group.getMembers().add(emp); cgdao.persist(group);
下面是日志中报告的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这样的接缝可能就是这个原因。 以下是这些方法的实现。 有没有红旗?
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; }
雇员
@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); }
继续感谢所有有帮助的人。
我非常怀疑你没有正确地覆盖equals
和hashCode
。 错误地覆盖它们会导致您遇到的行为(因为哈希键在地图中用作键)。 仔细检查你用equals
和hashCode
做了什么。
使用带有良好equals
和hashCode
带注释实体,此代码(逻辑上等效):
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();
在我的机器上产生以下输出:
08:10:32.426 [main] DEBUG ohedAbstractFlushingEventListener - 处理冲洗时间级联 08:10:32.431 [main] DEBUG ohedAbstractFlushingEventListener - 脏检查集合 08:10:32.432 [main] DEBUG org.hibernate.engine.CollectionEntry - 集合脏:[com.stackoverflow.q2649145.CohortGroup.members#1] 08:10:32.432 [main] DEBUG org.hibernate.engine.CollectionEntry - 集合脏:[com.stackoverflow.q2649145.Employee.memberGroup#1] 08:10:32.443 [main] DEBUG org.hibernate.engine.Collections - 找到的集合:[com.stackoverflow.q2649145.CohortGroup.members#1],是:[com.stackoverflow.q2649145.CohortGroup.members#1](初始化) 08:10:32.448 [main] DEBUG org.hibernate.engine.Collections - 找到的集合:[com.stackoverflow.q2649145.Employee.memberGroup#1],是:[com.stackoverflow.q2649145.Employee.memberGroup#1](未初始化) 08:10:32.460 [main] DEBUG ohedAbstractFlushingEventListener - 刷新:0次插入,0次更新,0次删除2个对象 08:10:32.461 [main] DEBUG ohedAbstractFlushingEventListener - 刷新:0(重新)创作,2个更新,0个删除到2个集合 08:10:32.463 [main] DEBUG org.hibernate.pretty.Printer - 列出实体: 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 ohpcAbstractCollectionPersister - 插入集合:[com.stackoverflow.q2649145.CohortGroup.members#1] 08:10:32.480 [main] DEBUG org.hibernate.jdbc.AbstractBatcher - 即将打开PreparedStatement(打开PreparedStatements:0,全局:0) 08:10:32.491 [main] DEBUG org.hibernate.SQL - 插入MYSITE_RES_COHORT_GROUP_STAFF(COHORT_GROUPID,USERID)值(?,?) Hibernate:插入MYSITE_RES_COHORT_GROUP_STAFF(COHORT_GROUPID,USERID)值(?,?) 08:10:32.496 [main] TRACE org.hibernate.type.LongType - 将'1'绑定到参数:1 08:10:32.497 [main] TRACE org.hibernate.type.LongType - 将'1'绑定到参数:2 08:10:32.499 [main] DEBUG ohpcAbstractCollectionPersister - 完成插入集合:插入1行
插入前没有删除!
顺便说一下,请注意,在处理双向关联时,您应该在两侧设置链接,就像我在组和员工上所做的那样。
或者在您的类上添加防御性链接管理方法,例如在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); }
我有同样的问题,并且一些试验和错误发现如果我使用Set而不是List作为我的集合,则不会发生删除。 令人恼火,因为我正在使用JSF和UI组件只会迭代列表。 但就是这样。
正如其他人所建议的那样,它可能是hashcode
或equals
的问题。
具体来说:Hibernate代理导致你在equals
方法中使用的instaceof
问题。 这说明了坏消息。
看看这个: http : //community.jboss.org/wiki/ProxyVisitorPattern
您必须在CohortGroup
和Employee
实体上定义hashCode()
和equals()
。 这可以由IDE自动完成,它可以是主键(有时不是一个好主意),也可以是业务键(最好)。
阅读这篇文章 。
插件按照我期望的方式进行操作。 感谢Pascal和z5h,我学到了很多东西。 我相信我已经正确实现了hashCode和equals。 这从来没有解决过我的问题。 相反,我已经实施了一个中间实体。
以下是我的Employee,CohortGroup和现在的CohortGroupMemeber类中的映射。
雇员:
@OneToMany(mappedBy="member") public List getMemberGroups(){ return memberGroups; } public void setMemberGroups(List grps){ memberGroups = grps; }
CohortGroupMember
@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; }
CohortGroup
@OneToMany(mappedBy="group") public List getMembers(){ return members; } public void setMembers(List emps){ members = emps; }
我遵循的这本书是Java Persistence with Hibernate第7.2.3章
在持久化上下文中加载对象并调用merge(如果存在)并保存(如果不存在)。
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();
- 集成了spring 3,hibernate 3,maven和mysql
- JPA – 使用mappedBy属性来定义拥有实体的不同之处
- Hibernate在更新集合时删除孤立
- 如何创建支持通用ID的通用实体模型类,包括自动生成的ID?
- @BatchSize使用聪明还是愚蠢?
- 在什么条件下我们需要在数据库中使用复合键
- ClassCastException在Hibernate / Spring 4升级后,无法将Proxy36强制转换为SessionImplementor
- 使用JBoss和Spring在Java Web应用程序之间共享业务对象实例的最佳方法是什么?
- 嵌套事务用例中的外部事务没有看到数据库中持久存在的更新(JPA,MySQL,Spring Framework和Hibernate)