实体A引用(多对一)实体B,具有从B到A的反向(映射)引用。还有引用A到C和反向引用C到A. 当我发出entityManager.remove(A)然后flush()时,“删除”不是gerenated!但也没有例外。就像没有调用remove()一样。为什么会这样? 如果在remove()之前我们从反向引用B.listOfA和C.listOfA中提取A,则会按预期生成“delete”。
另请注意my another question我得出结论,orphanRemoval并不总是按预期工作。现在我开始怀疑可能级联效果很好,但是之后实际的级联删除就像我在这里描述的那样被“吞噬”了。
答案 0 :(得分:5)
看看这个answer。基本上,如果对其应用持久化操作,JPA规范要求删除的实体再次被管理。
要验证这是否真的发生了,请为org.hibernate
包启用跟踪日志级别,并搜索以下日志条目:
un-scheduling entity deletion ...
为避免任何不可预测的行为,建议从加载相同会话/事务的所有其他实体实例中删除对已删除实体的引用。
答案 1 :(得分:0)
我遇到了这个问题。 即使show_sql已启用:
<property name="hibernate.show_sql" value="true"></property>
没有输出,并且删除命令被静默忽略。
问题与OneToMany关系有关,其中: 待办事项1 --- * todoitem
环境是: -JSF -Wildfly 18(JPA默认实现-休眠) -PostgreSQL 10
试图在任何一侧删除实例都会失败,并且在服务器的输出上没有相应的“ delete”命令,并且没有任何类型的异常消息。
解决方案
首先,我将Wildfly18 / JBoss文档在示例中建议的多方代码从以下位置切换:
// @Override
// public void delete(Todoitem todoitem) {
// if (todoitem == null) {
// return;
// }
// if (!emPg.contains(todoitem)) {
// todoitem = emPg.merge(todoitem);
// }
// emPg.remove(todoitem);
// emPg.flush();
// emPg.clear();
// }
等效形式:
@Override
public void delete(Todoitem todoitem) {
if (todoitem == null) {
return;
}
Todoitem ti = emPg.find(Todoitem.class, todoitem.getId());
if(ti == null) {
return;
}
emPg.remove(ti);
emPg.flush();
emPg.clear();
}
不幸的是,我得到了相同的结果-删除默默地忽略了。
然后,我怀疑数据库,因为休眠处理自己的密钥。在实施过程中我做了很多测试... 为了确保一致性问题,我决定清空数据库,删除关系双方的内容。 然后,我使用应用程序的资源(没有SQL命令)创建了新的实体实例和关系,因为除实体移除之外,其他所有东西都运行良好。 之后,我使用SQL命令检查了数据库关系,以确保一切正常。
接下来,我再次尝试了一项新测试,但这一次它成功了。
然后,我还原了代码,取消了注释的代码的注释,反之亦然,然后再次进行了测试。 测试再次失败,返回了相同的结果-默默地忽略了remove。
我再次将代码重新设置为先前的条件测试,以确认结果。 确认成功,确认了对两个问题的怀疑,数据库和代码实现。
由于是个好消息,我在“一个”方面重复了同样的操作(下面的代码-注释的代码是从Wildfly 18文档继承的第一个代码,如上所述)。
发件人:
// @Override
// public void delete(Todo todo) {
// if(todo == null) {
// return;
// }
// if (!emPg.contains(todo)) {
// todo = emPg.merge(todo);
// }
// //todoitemDao.deleteAll(todo);
// emPg.remove(todo);
// emPg.flush();
// }
收件人:
@Override
public void delete(Todo todo) {
if (todo == null) {
return;
}
Todo t = emPg.find(Todo.class, todo.getId());
if(t == null) {
return;
}
emPg.remove(t);
emPg.flush();
emPg.clear();
}
再次重复测试,但是这次不删除Todoitem实例(“很多”面),而是删除Todo实例(“一个”面)。
问题解决了。成功。
重要说明:
直接在数据库上使用SQL语句检查删除测试。 有时,由于缓存问题或代码实现错误,实例似乎没有被删除,需要分开对待。