【问题标题】:Hibernate deleting orphans when updating collection更新集合时休眠删除孤儿
【发布时间】:2010-11-21 06:00:04
【问题描述】:

我发现从 Hibernate 中的集合中删除时没有删除孤立记录。我一定是做错了什么,(这是 Hibernate-101!),但我找不到它..

鉴于以下情况:

public class Book {
    @ManyToOne
    @NotNull
    Author author;
}
public class Author
{
    @OneToMany(cascade={CascadeType.ALL})
    List<Book> books;
}

还有如下更新代码:

Author author = authorDAO.get(1);
Book book = author.getBooks().get(0);
author.getBooks().remove(0);
authorDAO.update(author);

作者DAO sn-p:

@Override
public void update(T entity) {
    getSession().update(entity);
}

以下测试失败:

Author author = author.get(1);
assertEquals(0,author.getBooks().size()); // Passes
Book dbBook = bookDAO.get(book.getId())
assertNull(dbBook); // Fail!  dbBook still exists!
assertFalse(author.getBooks().contains(dbBook) // Passes!

总之,我发现:

  • 虽然图书已从作者的图书收藏中删除,但它仍存在于数据库中
  • 如果我检查 book.getAuthor().getBooks(),则该集合中不存在该书

这“感觉”就像我没有适当地刷新会话或强制更新 - 但我不确定我应该在哪里这样做。沿着这条脉络,其他可能会产生影响的点:

  • 我在用@RunWith(SpringJUnit4ClassRunner.class) 装饰的 JUnit 测试中执行上述操作
  • 我最初在一个用@Transactional 装饰的更新例程中遇到了这个问题,但是,我后来在一个普通的旧 JUnit 测试中重新创建了它。

任何建议将不胜感激!

编辑:已经感谢所有反馈。除了下面的 cmets,我还向父级添加了 @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN),所以现在是:

public class Author
{
    @OneToMany(cascade={CascadeType.ALL})
    @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    List<Book> books;
}

我仍然发现相同的结果。我一定错过了一些简单的东西。

【问题讨论】:

    标签: java hibernate orphan


    【解决方案1】:

    对于寻找解决方案的人:现在在 Hibernate 中,分别。 JPA 2.0,这是正确的方法:

    @OneToMany(orphanRemoval=true)
    

    【讨论】:

      【解决方案2】:

      你没有做错任何事。您只是没有删除子实体。您可以使用子实体的显式 remove() 来执行此操作(除了您正在执行的操作之外),也可以使用导致孤立记录被删除的注释。

      另外,值得一提的是CascadeType.DELETE 也不会删除孤儿。这意味着别的东西。见JPA CascadeType.ALL does not delete orphans.

      基本上要自动执行此操作,您需要在父集合中执行此操作:

      org.hibernate.annotations.CascadeType.DELETE_ORPHAN
      

      【讨论】:

      • 我已添加此注释,但仍无法正常工作 - 结果与以前相同。
      • 您是否也将书中的作者参考设置为空?
      • 不,我认为这是 DELETE_OPRHAN 注释的重点?
      • 您仍然需要自己管理 Java 关系。这意味着如果关系是双向的,则必须在子级中将父级设置为 null。
      【解决方案3】:

      @OneToMany注解中的cascade选项是一个数组,你想要的是:

      @OneToMany(cascade={CascadeType.ALL, CascadeType.DELETE_ORPHAN})
      

      【讨论】:

      • 不会 CascadeType.ALL 也覆盖 CascadeType.DELETE_ORPHAN 吗?
      • 这个答案已经 9 岁了。它可能不再相关了。
      【解决方案4】:

      如果您想要“传递依赖”行为,请尝试使用以下注解。

      @org.hibernate.annotations.Cascade(CascadeType.DELETE_ORPHAN)

      【讨论】:

        【解决方案5】:

        请添加@onDelete 也许这对你有用

        public class Author
        {
            @OneToMany(cascade={CascadeType.ALL})
            @OnDelete(action = OnDeleteAction.CASCADE)
            @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
            List<Book> books;
        }
        

        【讨论】:

        • 嗨。这也没有效果。
        • 你是提交会话还是在删除后刷新它?
        【解决方案6】:

        看起来您可能缺少 ma​​ppedBy 注释。试试:

        public class Book {
          @ManyToOne
          @NotNull
          Author author;
        }
        public class Author {
          @OneToMany(mappedBy="author", cascade={CascadeType.ALL})
          List<Book> books;
        }
        

        【讨论】:

          【解决方案7】:

          我知道我迟到了,我意识到关于这个话题已经说了很多,但恕我直言,我不会使用 delete-orphans 作为级联选项。我宁愿在删除父级之前手动删除子级关联。一个轻微的疏忽……一长串的关联可以在一秒钟内被删除。是的!我同意在某些情况下这可能正是人们想要的。

          【讨论】:

            猜你喜欢
            • 2012-02-07
            • 2018-02-23
            • 1970-01-01
            • 1970-01-01
            • 2011-01-02
            • 2012-10-22
            • 1970-01-01
            • 1970-01-01
            • 2016-02-15
            相关资源
            最近更新 更多