【问题标题】:OneToMany relationship orphans are not removed from the DBOneToMany 关系孤儿不会从数据库中删除
【发布时间】:2018-02-21 21:17:09
【问题描述】:

最初这个问题/错误发布在 Hibernate 的 JIRA 上:https://hibernate.atlassian.net/browse/HHH-12311

我的日志属性设置为:

logging.level.org.hibernate.SQL: TRACE
logging.level.org.hibernate.event.internal: TRACE
logging.level.org.hibernate.engine.spi.CollectionEntry: TRACE
logging.level.org.hibernate.engine.spi: TRACE
logging.level.org.hibernate.engine.internal: TRACE

我有两个实体:JobStep Job 与标有orphanRemoval = True 的 Step 具有 oneToMany 关系。

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinTable(name = "JOB_STEP")
private List<Step> steps;

预期的行为是当从steps 列表中删除某个步骤时,应在STEPJOB_STEP 表上执行DELETE 查询。


第一种情况,执行以下代码时会出现预期的行为:

Job job = new Job("Test");
Step step = new Step("Test");
job.addStep(step);
repository.save(job);
job.removeStep(step);
repository.save(job);

我看到三个预期的日志消息:

o.h.e.i.AbstractFlushingEventListener: Flushed: 0 insertions, 0 updates, 1 deletions to 2 objects
org.hibernate.SQL: delete from job_step where job_id=?
org.hibernate.SQL: delete from step where id=?

第二种情况,当orphanRemoval = true 不调用从数据库中删除孤儿时。

Job job = new Job("Test");
Step step = new Step("Test");
repository.save(job); //This causes the bug to happen
job.addStep(step);
repository.save(job);
job.removeStep(step);
repository.save(job);

上述代码执行后,我仍然可以看到DB中的STEP和JOB_STEP表中的条目。

打印以下日志:Flushed: 0 insertions, 0 updates, 0 deletions to 2 objects


几周以来,我一直试图通过调试 Hibernate 的源代码来找出这个问题的根本原因。但这并没有真正帮助。但是,我注意到一些可能对您有帮助的异常情况:

1) 在调试过程中,我从org.hibernate.engine.spi.CollectionEntry 偶然发现了这个方法resetStoredSnapshot,它基本上只是擦除了Steps 的存储快照,后来导致Hibernate 找不到孤儿。而在第一种情况下,当 Hibernate 按预期工作时,resetStoredSnapshot 根本不会执行。

2) 我注意到 java.util.List of Steps 一旦被 Hibernate 转换为 org.hibernate.collection.PersistentList 就会开始异常工作


重现错误的工作区在这里:https://github.com/yeralin/ReproduceBug

【问题讨论】:

  • 对于 50 pt 的赏金,我会看看。基本上,您希望它为您概述的案例执行删除或解释为什么它不能/没有完成?
  • 不久前我有一个类似的问题,但从未找到根本原因。 stackoverflow.com/questions/28487796/…
  • 必须在管理实体时删除子项,如果您在持久性上下文之外删除子项(例如在客户端/前端左右),那么您尝试使用新的删除 children ,孩子不会被删除......所以我不知道 job.removeStep(step); 是否在 Persistence 上下文中或也不

标签: java hibernate jpa


【解决方案1】:

根据the doc on save

Use the returned instance for further operations as the save operation might have changed the entity instance completely.

你应该这样做:

job = repository.save(job);

step保存后也可能不一样。

要记住这一点,想想@Id。当您保存实体时,您可能会获得一个具有更新 id 的新对象。像step这样的孩子也是如此。

【讨论】:

  • 这不是很明显,我遵循的所有教程都没有真正强调这一点。谢谢
【解决方案2】:

首先,我不知道您为什么要为 OnToMany 关系设置单独的表。您可以将 一对多 关系与jobID 实现为一个steps 表内的列。

要正确实现OnToMany关系,请关注https://vladmihalcea.com/the-best-way-to-map-a-onetomany-association-with-jpa-and-hibernate/

现在回答你的问题:

如果您有 Bi-Directional 关系,您需要将其父级设置为 null 来移除孤儿

job.removeStep(step);
step.setJob(null);

也看看这个答案https://stackoverflow.com/a/3071125/3425489

【讨论】:

    猜你喜欢
    • 2012-09-16
    • 1970-01-01
    • 1970-01-01
    • 2015-10-06
    • 2018-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-23
    相关资源
    最近更新 更多