我在休眠方面有多对多的关系。 数据库表是:
events(event_id,name)
speaker(speaker_id,name)
event_speaker(event_id,speaker_id)
event.hbm.xml
<set name="speakers" table="event_speakers" cascade="save-update">
<key column="event_id"/>
<many-to-many class="com.manytomany.model.Speaker"/>
</set>
speaker.hbm.xml
<set name="events" table="event_speakers" cascade="save-update">
<key column="speaker_id"/>
<many-to-many class="com.manytomany.model.Event"/>
</set>
我在Event.java和Speaker.java中实现了.equals和hashcode方法
Event.java
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
Event event = (Event)obj;
return this.id == event.id;
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return (int)id;
}
Speaker.java
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
Speaker speaker = (Speaker)obj;
return this.id == speaker.id;
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return (int)id;
}
这是我的逻辑
session.beginTransaction();
Event event = (Event) session.createCriteria(Event.class).add(Restrictions.eq("id", 1L)).uniqueResult();
event.setSpeakers(new HashSet());
Speaker speaker = new Speaker();
speaker.setName("11");
Speaker speaker2 = new Speaker();
speaker2.setName("12");
event.getSpeakers().add(speaker);
event.getSpeakers().add(speaker2);
session.save(event);
session.getTransaction().commit();
当我在上面运行代码时,hibernate就像这样执行
Hibernate: select this_.event_id as event1_0_0_, this_.event_name as event2_0_0_ from events this_ where this_.event_id=?
Hibernate: select max(speaker_id) from speakers
Hibernate: insert into speakers (speaker_name, speaker_id) values (?, ?)
Hibernate: delete from event_speakers where event_id=?
Hibernate: insert into event_speakers (event_id, elt) values (?, ?)
为什么要从连接表中删除,我想在连接表中插入新行而不是删除。
答案 0 :(得分:0)
在我看来,你的扬声器是平等的。我会调查
的布尔返回值event.getSpeakers().add(speaker2);
我的猜测是,当在集合之外检查相等性时,扬声器的id为空(对象仍然是瞬态的)。因此,使用生成的id进行相等是危险的。
一个修复:摆脱Event和Speaker上的equals()和hashcode()方法。
关注:对于多对多的集合,在加载单个实体时存在加载整个数据库的风险。如果你加载了一个扬声器,它将获取所有扬声器的事件,而这些事件又将获取所有那些事件的扬声器......呀。即使您为延迟加载标记了集合,也可以为使用它们的人创建一个雷区。
另一种方法:您可以使用合成并在event_speaker表周围创建一个EventSpeaker实体。然后,您将创建DAO和服务层,为您提供所需的方法,例如获取扬声器的所有事件的能力,反之亦然。如果证明有必要,它还允许您添加SpeakerEvent组合的唯一属性。