如果有其他孩子,则对孩子的Hibernate删除不起作用

时间:2018-05-24 11:48:18

标签: java hibernate

有一个实体'地址'和另一个实体'建筑物' 在一个地址可以有多个建筑物。

在building.java上我的地址定义为:

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "ADDRESS_ID_REF")
public Address getAddress() {
    return this.address;
}

地址构建定义为:

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "address")
public Set<Building> getBuildings() {
    return this.buildings;
}

试图做的时候 em.remove(building) 它确实有用

  • 只在一个地址建设时很好
  • 当同一地址有两座建筑物时>

坏情况的构造与好的情况完全相同,再加上参考同一地址将第二个建筑物插入数据库。

  • 插入地址值(&#39;地址123&#39;,[...]);
  • 插入建筑物价值(&#39; building234&#39;,&#39; address123&#39;,[...]);
  • 插入建筑物价值(&#39; building235&#39;,&#39; address123&#39;,[...]);

在坏的情况下(hibernate没有做任何删除)我仍然可以删除数据库中的行(delete from building where building_id = '123')。没有关于引用的SQL错误。

在类似的线程中,我读到在这种情况下通常会留下引用,使得hibernate正确无法删除此实体。

不幸的是,我也没有得到任何hibernate的log4j输出,也没有异常发生。所以我不知道hibernate在这个地方的问题是什么。

我的log4j.properties适用于我的记录器。输出按预期写入控制台。 但我没有得到任何Hibernate日志记录。 我在另一个帖子中读到这个记录器应该给我一些提示: org.hibernate.event.internal.DefaultPersistEventListener

log4j.rootLogger=TRACE, A1
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p %c - %m%n

log4j.category.com.myproject.mypackage=INFO
log4j.category.com.myproject.mypackage.myclass=DEBUG

log4j.category.org.hibernate.event.internal.DefaultPersistEventListener=TRACE
log4j.category.org.hibernate=TRACE
log4j.category.org.springframework=TRACE

当在persistence.xml show_sql中设置为true时,我将把SQL写入控制台。在那里我可以看到没有执行删除sql。但我没有看到任何错误。

<property name="hibernate.show_sql" value="true" />
<property name="hibernate.format_sql" value="true" />

在大多数情况下写在其他线程中似乎有一些必须首先删除的引用。 但在我的情况下,我的实体是子对象,这意味着我不希望外国人建立指导解决问题。 另外,我可以通过SqlDeveloper直接删除构建行。 从

更改代码时
em.remove(building)

em.remove(address)

由于级联,所有三个实体都被删除。但这不是我想要的,我只想删除单个建筑物。 我想要得到它,我需要看到缺少的hibernate loggings(希望有一些)。

如果您需要更多信息,请索取。 提前谢谢。

2 个答案:

答案 0 :(得分:1)

(这将是一个评论,但我没有足够的声誉)你想要实现什么或更好的什么不起作用?删除建筑物不应删除地址,因为@ManyToOne注释中没有级联选项。如果你试图删除建筑物从建筑物集中删除它,你需要在@OneToMany注释中使用orphanRemoval = true

编辑(阅读评论后)

最简单的方法是: 将orphanRemoval = true添加到@OneToMany地址映射。比

Building b .... // current Object to be deleted
b.getAddress().getBuildings().remove(b);
b.setAddress(null);
em.merge(a);

这段代码

b.getAddress().getBuildings().remove(b);
b.setAddress(null);

您可以在地址实体中创建单独的方法,例如

public void removeBuilding(Building b){
    buildings.remove(b);
    b.setAddress(null);
}

答案 1 :(得分:0)

我不确定框架是否正确和有意,但我找到了解决方案/解决方法:

而不是只做:

em.remove(b);

我现在在做:

Building b .... // current Object to be deleted
Address a = b.getAddress();
Set<Building> bSet = a.getBuildings();
bSet.remove(b);
em.remove(b);

这很好用。 希望这是有效的。

解释可能是: 即使事务方法结束,删除子实体也不会更新子项的父列表(意味着提交已完成)。

我原本以为在删除子实体并进行提交时,会从数据库中删除该实体。 然后,当在新的事务中加载aparent实体时,其所有子权限都从数据库中进行后退,因此在父端不再列出已删除的子实体。 也许(虽然是事务执行)一些数据保存在缓存中?

正如在另一条评论中所说,只是在地址实体中添加orphanRemoval = true给cascadeAll-Line不会产生任何影响。