hibernate insert в коллекцию вызывает удаление, а затем все элементы в коллекции должны быть вставлены снова
у меня есть много, чтобы отношения CohortGroup и сотрудник. Каждый раз, когда я вставляю сотрудника в спящий режим CohortGroup, удаляет группу из таблицы разрешения и снова вставляет все члены плюс новый. Почему бы просто не добавить новый?
Аннотация В группе:
@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;
}
другая сторона в сотруднике
@ManyToMany(mappedBy="members",cascade = { PERSIST, MERGE, REFRESH } )
public List<CohortGroup> getMemberGroups(){
return memberGroups;
}
snipit код
Employee emp = edao.findByID(cohortId);
CohortGroup group = cgdao.findByID(Long.decode(groupId));
group.getMembers().add(emp);
cgdao.persist(group);
ниже sql сообщается в log
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;
}
я добавил метод addMember в CohortGroup, который добавляет к обеим сторонам отношения:
public void addMember(Employee emp){
this.getMembers().add(emp);
emp.getMemberGroups().add(this);
}
продолжение Спасибо всем, кто помогает.
6 ответов
Я очень подозреваю, что вы не переопределяете 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 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);
}
У меня была эта же проблема и с некоторыми проб и ошибок обнаружили, что удаление не происходит, если я использовал набор вместо списка в моей коллекции. Раздражает, учитывая, что я использую JSF и компоненты пользовательского интерфейса будут только перебирать списки. Но это так.
как другие предположили, это, вероятно, проблема с hashcode
или equals
.
в частности: прокси-серверы Hibernate вызывают проблемы с instaceof
что вы используете в своем equals
метод. Что заклинания плохие новости.
вы должны определить hashCode()
и equals()
на CohortGroup
и Employee
объекты. Это может быть сделано автоматически вашей IDE, и это может быть либо на первичном ключе (иногда не очень хорошая идея), либо на бизнес-ключе (предпочтительнее).
читать в этой статье.
у меня есть вставки, действующие так, как я ожидаю от них сейчас. Благодаря Паскалю и z5h, я многому научился. Я считаю, что у меня есть hashCode и equals реализованы правильно. Это никогда не решало проблему для меня. Вместо этого я реализовал промежуточную сущность.
для чего это стоит ниже, это отображение в моем сотруднике, CohortGroup, а теперь CohortGroupMemeber занятия.
сотрудник:
@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;
}
книга, которую я следовал для этого, - это Java Persistence с Hibernate chapter 7.2.3
загрузите объект в контексте персистентности и вызовите слияние, если существует, и сохраните, если не существует.
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();