代码之家  ›  专栏  ›  技术社区  ›  Maksim Gumerov

默默忽略remove()

  •  4
  • Maksim Gumerov  · 技术社区  · 9 年前

    有实体A引用(多对一)实体B,从B到A的反向(映射)引用也有引用A到C和反向引用C到A。 当我发布entityManager时。remove(A)然后flush(),“delete”不触发!但也没有例外。就像根本没有调用remove()一样。为什么会这样? 如果在remove()之前,我们从反向引用B.listOfA和C.listOfB中提取A,则会按预期生成“delete”。

    另请注意 my another question 我得出的结论是,孤儿移除并不总是如预期的那样有效。现在我开始怀疑级联可能效果很好,但在实际的级联移除之后,就像我在这里描述的那样被“吞没”了。

    2 回复  |  直到 7 年前
        1
  •  10
  •   Community Mike Kinghan    7 年前

    看看这个 answer 基本上,JPA规范要求,如果持久化操作被应用于被移除的实体,则该实体将再次被管理。

    要验证这是否真的发生,请启用跟踪日志级别 org.hibernate 打包并搜索日志条目,如:

    un-scheduling entity deletion ...
    

    为了避免任何不可预测的行为,建议从加载同一会话/事务的所有其他实体实例中删除对已删除实体的引用。

        2
  •  0
  •   Andre Dias    4 年前

    我有这个问题。 即使启用了show_sql:

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

    没有输出,remove命令被默默忽略。

    问题围绕一对多关系,其中: 待办事项1---*待办事项

    环境是: -JSF语言 -Wildfly 18(JPA默认实现-Hibernate) -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();
    }
    

    不幸的是,我得到了同样的结果——删除被默默忽略。

    然后,我怀疑数据库,因为hibernate处理自己的密钥。我在实施过程中做了很多测试。。。 为了确定一致性问题,我决定清空数据库,删除关系双方的内容。 然后,我使用应用程序的资源(没有SQL命令)创建了新的实体实例和关系,因为除了实体删除之外,其他工作都很顺利。 之后,我使用SQL命令检查了数据库关系,以确保一切正常。

    接下来,我再次尝试了一个新的测试,但这次成功了。

    然后我恢复了代码,取消注释注释的代码,反之亦然,并再次测试。 测试再次失败,返回相同的结果,忽略删除。

    我再次将代码设置为先前的条件测试,以确认结果。 确认是成功的,确认了对两个问题的怀疑,即数据库和代码实现。

    由于好消息,我在“One”一方重复了同样的内容(下面的代码-注释代码是从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语句检查删除测试。 有时,由于缓存问题或代码实现错误,实例似乎没有被删除,需要分开处理。