让JPA的一对多关系生效?

3

我已经写了一个非常基础和朴素的一对多关系,它是在聊天组件和其聊天消息之间建立的:

@OneToMany
List<ChatMessage> chatMessages;

这基本上是行得通的,即执行类似以下操作:
ChatMessage chatMessage = vo.toDomainObject();
chatMessage.setDate(new Date());
//Add the message to the chat component
em.getTransaction().begin();
em.persist(chatMessage);
chat.addChatMessage(chatMessage);
em.persist(chat);
em.getTransaction().commit();

完成任务。但是,通过查看SQL日志,我发现每次都会重新存储整个聊天消息集合。显然,考虑到聊天消息可能很快增加到数千条,这是我无法承受的。

每个聊天消息重复执行的SQL如下:

Hibernate: insert into BaseComponent_ChatMessage (BaseComponent_id, chatMessages_id) values (?, ?)

前缀:

Hibernate: delete from BaseComponent_ChatMessage where BaseComponent_id=?

由此我得出结论,Hibernate无法知道我们不是在处理一整组新对象,并且应该保留已经存在的对象。

我相信有一种方法可以添加(并持久化)关系的多个成员中的一个,但我似乎找不到如何做到。

2个回答

2
我发现避免每次持久化整个聊天消息列表的唯一方法是在聊天组件和其聊天消息之间建立双向关系。
@OneToMany(cascade={CascadeType.PERSIST,CascadeType.MERGE}, fetch=FetchType.LAZY, mappedBy="parent")
List<ChatMessage> chatMessages;

@ManyToOne
@JoinColumn(name="OWNER_CHAT_COMPONENT_ID", nullable=false)
private ChatComponent parent;

在addChatMessage函数中,我可以简单地向聊天组件添加消息,而无需将其持久化,然后持久化聊天组件即可。这样做非常好用。

    em.getTransaction().begin();
    chat.addChatMessage(chatMessage);
    em.persist(chat);
    em.getTransaction().commit();

1

覆盖您的ChatMessage类的hashCodeequals方法,以便Hibernate知道这些是相同的对象。

使用您的IDE生成hashCode()和equals()。在Eclipse中,右键单击> Source > Generate hashCode and equals,并选择作为实体的@Id属性。

此外,尝试将cascade=CascadeType.ALL属性添加到@OneToMany中。


嗨Bozho,这确实很有道理。但是,我可以看到发出的第一条语句是:Hibernate:delete from BaseComponent_ChatMessage where BaseComponent_id=?...这似乎表明ChatComponent(ChatComponent在此处继承自BaseComponent)未被识别为已存在。我尝试在两个类中实现hashCode()方法,只需让它返回实体的id即可。不过我不确定这是否是正确的方法,而且我对equals方法该怎么做也有点困惑。无论如何,非常感谢您,这绝对是一个好的线索 :-) - user162346
嗯,我已经尝试了在关系的两端使用Eclipse生成hashCode和equals的所有可能组合,但我仍然有n+1个插入:(无论如何还是谢谢! - user162346
尝试添加cascade=CascadeType.ALL属性。 - Bozho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接