【问题标题】:Can't quite understand how to delete fields properly with Hibernate不太明白如何使用 Hibernate 正确删除字段
【发布时间】:2015-07-04 18:02:11
【问题描述】:

我的数据库中有多对多关系(实体是参与者和事件)

//part of participant model
@ManyToMany(fetch = FetchType.LAZY , cascade = { CascadeType.PERSIST, CascadeType.MERGE})
    @JoinTable(name = "participant_event",
            joinColumns = {@JoinColumn(name = "participant_id")},
            inverseJoinColumns = {@JoinColumn(name = "event_id")})

//part of event model 
  @ManyToMany(fetch = FetchType.LAZY, mappedBy = "events", cascade = CascadeType.ALL)

就在此时,删除一个活动会导致删除所有要访问该活动的参与者。删除事件模型中的CascadeType.ALL 会导致删除事件后没有结果(删除我的意思是.remove)。仅删除 Event 并保留所有参与者的正确方法是什么?

代码是here

【问题讨论】:

  • 移除级联至少应该导致删除 SQL 查询被执行。它可能会失败,从而导致抛出异常,因为参与者仍在引用被删除的事件。解决方法很简单:从所有参与者中删除该事件,然后删除该事件。
  • 在删除事件之前调用flush()。这将强制 Hibernate 在从事件表中删除之前从连接表中删除。
  • @JBNizet 现在注意到了一件奇怪的事情——我用event_id=1flush() 从字段中清除了participant_event 表,尝试使用id=1 的.remove(event) 并显示Key (event_id)=(3) is still referenced from table participant_event(不是event_id=1!!)。但是如果我从函数中return event; 它只返回一个带有event_id=1 的事件,它可以是带有 FetchType 的东西吗?
  • 事件之间还有其他关联吗?你能发布完整的 Event 类,以及你用来删除它的完整代码吗?
  • 代码应该在问题本身中。我注意到你仍然没有调用flush(),甚至没有调用remove()。您还与 Task 有关联,并且 Task 再次具有具有级联 ALL 的 ManyToOne,这意味着删除任务将尝试删除任务的事件。这没有意义。

标签: java database hibernate jpa many-to-many


【解决方案1】:

在多对多关联中,CascadeType.REMOVE is not desirable,因为它删除了实际的实体(而不仅仅是它们关联的链接表条目)。

删除关联的正确方法是分离实体:

public void removeEvent(Event event) {
    events.remove(event);
    event.setParticipant(null);
}

要删除Event,您必须从所有Participants 中删除。为此,您必须执行以下操作:

Event deletableEvent = ...;

for(Iterator<Participant> participantIterator = event.getParticipnts(); participantIterator.hasNext();) {
    Participant participant = participantIterator.next();
    participant.getEvents().remove(deletableEvent);
    participantIterator.remove();
}

entityManager.flush();
entityManager.remove(deletableEvent);

【讨论】:

  • .remove(event) 对仍然存在的引用导致相同的异常(如果我没听错,我们从 EntityManager 调用此方法)
  • 看起来我现在正在做那件事,但由于某种原因.remove() 试图删除不是我试图删除的唯一事件。检查我对问题帖子的评论
  • 您需要激活 Hibernate SQL 日志并将它们与您现在使用的实际代码和实际实体一起粘贴到您的问题中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-15
  • 1970-01-01
  • 1970-01-01
  • 2020-08-20
  • 1970-01-01
  • 1970-01-01
  • 2021-12-29
相关资源
最近更新 更多