如何处理删除具有外键关系的许多JPA实体

Joe*_*Joe 0 hibernate jpa

问题:实体(比如用户)在UI中以分页方式显示.UI还显示针对每个实体的复选框,以便管理员可以多选用户并删除它们.很自然,这个实体通过外键关系与许多其他实体相关联(比如他创建的采购订单)

如果采购订单与某个用户相关联,则由于外键违规,将无法删除用户.类似地,User可能与许多其他此类表有关系.

如果无法删除实体,最好不要显示删除复选框.如果需要进行此类检查,则在为每个用户行构建用户列表页面时,需要查询从属表以查找可能的关系.如果有很多用户,这可能是非常昂贵的事情.

以优雅的方式解决这个问题的建议方法是什么?

Boz*_*zho 5

我想到了五种方式:

  1. cascade=CascadeType.DELETE(或ALL)声明所有依赖项.然后将删除所有内容,但这很少是所需的行为.
  2. 在任何地方显示复选框,逐个删除用户(使用session.remove()/ entityManager.remove())并捕获任何用户ConstraintViolationException.就像是:

    for (User user : usersToDelete) {
         try {
             entityManager.remove(user); // or dao.remove(), 
                                         // or someService.remove()
         } catch (Exception ex) {
             // verify if the there is `ConstraintViolationException` 
             // in the exception chain, and log a short message about the failure
             // If the exception is elsewhere, then log the whole exception
             // or rethrow
         }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,在这种情况下,您可能需要设置它FlushMode,EntityManager以便在正确的时间抛出异常.

  3. 编写特定于数据库的代码,用于检查用户(或同一场景下的任何对象)的约束.我这样做了一次,因为它允许准确显示哪些记录取决于当前记录.我在删除时执行了特定于数据库的检查,因此所有用户都有了复选框.

  4. 按照你说的做,但是将所有结果存储在某种缓存中(无论是你自己的缓存还是Hibernate的缓存,你都可以更容易控制).因此,很少进行昂贵的操作.另外,请考虑为用户列表使用分页.

  5. 尝试实现ON CASCADE SET NULL.如果有可能,我不会,也许是cascade=ALL+ nullable=true.检查这个帖子.如果您没有从实体生成数据库,那么juts会ON CASCADE SET NULL在数据库中设置它.

还有一个相关的建议:不要使用HQL进行删除,因为它忽略了Hibernate级联.