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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2649145/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 22:11:48  来源:igfitidea点击:

hibernate insert to a collection causes a delete then all the items in the collection to be inserted again

javahibernateormjpa

提问by Mark

I have a many to may relationship CohortGroup and Employee. Any time I insert an Employee into the CohortGroup hibernate deletes the group from the resolution table and inserts all the members again, plus the new one. Why not just add the new one?

我有很多关系 CohortGroup 和 Employee。每当我将员工插入 CohortGroup 时,休眠都会从解析表中删除该组并再次插入所有成员,以及新成员。为什么不直接添加新的?

The annotation in the Group:

组内注解:

@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;
}

The other side in the Employee

员工的另一面

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

Code snipit

代码片段

Employee emp = edao.findByID(cohortId);
CohortGroup group = cgdao.findByID(Long.decode(groupId));
group.getMembers().add(emp);
cgdao.persist(group);

below is the sql reported in the log

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

This seams really inefficient and is causing some issues. If sevral requests are made to add an employee to the group then some get over written.

这种接缝确实效率低下,并导致了一些问题。如果提出了将员工添加到组中的几个请求,那么有些请求会被覆盖。

Seams like equals and hashCode might be a reason for this. Below are the implementation for these methods. Any red flags?

像 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;
}

Employee

员工

       @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;
}

I have added an addMember method to the CohortGroup that adds to both sides of the relationship:

我向 CohortGroup 添加了一个 addMember 方法,该方法添加到关系的双方:

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

}

Continued thanks to all that are helping.

继续感谢所有提供帮助的人。

采纳答案by Mark

I have inserts acting the way I expect them to now. Thanks to Pascal and z5h, I have learned a lot. I believe I have the hashCode and equals implemented correctly. This never solved the problem for me though. Instead I have implemented an Intermediate Entity.

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

For what it is worth below are the mapping in my Employee, CohortGroup, and now CohortGroupMemeber classes.

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

Employee:

员工:

@OneToMany(mappedBy="member")
public List<CohortGroupMember> getMemberGroups(){
   return memberGroups;
}
public void setMemberGroups(List<CohortGroupMember> 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<CohortGroupMember> getMembers(){
    return members;
}
public void setMembers(List<CohortGroupMember> emps){
    members = emps;
}

The book I followed for this is Java Persistence with Hibernate chapter 7.2.3

我为此遵循的书是 Java Persistence with Hibernate 章节 7.2.3

回答by Pascal Thivent

I highly suspect that you're not overriding equalsand hashCodeproperly. Wrongly overriding them can lead to the kind of behavior you're experiencing (as the hash key is used as keys in maps). Double check what you did with equalsand hashCode.

我高度怀疑你没有正确地覆盖equalshashCode正确。错误地覆盖它们可能会导致您遇到的行为(因为哈希键用作映射中的键)。仔细检查你用equals和做了什么hashCode

Using yourannotated entities with good equalsand hashCode, this code (logically equivalent):

使用注明实体具有良好的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();

produces the following output on my machine:

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

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

No delete before the insert!

插入前不可删除!

By the way, note that you should set the link on bothsides when working with bi-directional associations, like I did on the group andon the employee.

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

Or add defensive link management methods on your classes, for example on CohortGroup:

或者在您的类上添加防御性链接管理方法,例如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);
}

回答by Marc

I had this same problem and with some trial and error found that the deletes did not occur if I used a Set instead of a List as my collection. Irritating, given that I'm using JSF and the UI components will only iterate over Lists. But there it is.

我遇到了同样的问题,并且通过一些试验和错误发现,如果我使用 Set 而不是 List 作为我的集合,则不会发生删除。令人恼火,因为我使用的是 JSF 并且 UI 组件只会遍历列表。但它就在那里。

回答by Tuan Nguyen Dang

I have same issue. I changed from List to Set. It work for me.

我有同样的问题。我从列表更改为设置。它对我有用。

@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;
}

回答by z5h

As others have suggested, it's probably a problem with hashcodeor equals.

正如其他人所建议的那样,这可能是hashcode或的问题equals

Specifically: Hibernate proxies cause problems with instaceofwhich you are using in your equalsmethod. That spells bad news.

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

Check this out: http://community.jboss.org/wiki/ProxyVisitorPattern

看看这个:http: //community.jboss.org/wiki/ProxyVisitorPattern

回答by Bozho

You have to define hashCode()and equals()on your CohortGroupand Employeeentities. This can be done automatically by your IDE and it can either be on the primary key (sometimes not a good idea) or on a business key (preferable).

你必须在你的和实体上定义hashCode()和。这可以由您的 IDE 自动完成,它可以位于主键(有时不是一个好主意)或业务键(最好)上。equals()CohortGroupEmployee

Read this article.

阅读这篇文章

回答by Gunjan

Load the object in persistence context and call merge if exist and save if not exist.

在持久化上下文中加载对象,如果存在则调用合并,如果不存在则保存。

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();