0

假设我们有一个旧的 Book 和 Authors 模型,两者都有 CRUD。当用户试图删除作者时,我想告诉她如果作者已经注册了书籍,她必须先删除作者的书籍。

也就是说,我只想删除一条记录,除非它没有任何引用,但如果有,我只想警告用户。

第一种方法:

到目前为止我一直在做的方式是这样的:

@PersistenceContext
private EntityManager em;

public void deleteAuthor(Author author){
    Long qtBooks = em.createQuery(
           "SELECT COUNT(b) FROM Book b WHERE b.author.id = :id")
           .setParameter("id", author.getId()).getSingleResult();
    if (qtBooks > 0) {
        throw IllegalArgumentException("This author has books registered");
    }
    em.remove(em.getReference(Author.class, author.getId()));
}

...并且在表示层(JSF bean)中,我捕获了异常,IllegalArgumentException在这种情况下是异常,并向用户显示其错误消息。

第二种方法:

当我使用 Spring 时,我知道另一种方法是DataIntegrityViolationException在表示层中捕获 Spring's 。然后,业务方法将只包含删除实体的代码:

public void deleteAuthor(Author author){
    em.remove(em.getReference(Author.class, author.getId()));
}

...然后表示层(在我的例子中是一个 JSF bean)可以捕获 Spring 异常:

@ManagedProperty("#{authorService}");
private AuthorService authorService;

public void deleteAuthor(Author author) {
    try {
        authorService.deleteAuthor(author);
        addGlobalInfo("Author deleted");
    } catch (DataIntegrityViolationException e) {
        addGlobalError("This author already has books associated");
    }
    redirect(getRequestURL());
}

现在,我使用第一种方法已经有一段时间了,我发现第二种方法更容易编写。我的问题是,除了使用这个特定的异常使我的应用程序更依赖于 Spring 之外,使用第二种方法的缺点是什么?第一个的真正优点是什么?到底好不好?是否有第三种更好的方法来使用 JPA 执行此操作?

由于这两种方法都依赖于捕获一些异常(除了第一个在尝试更改数据库中的任何内容之前抛出),我真的不知道如何决定。

4

1 回答 1

1

两种方法都很好,但第二种方法不太灵活:

  • 如果您在涉及多个实体的较大事务中使用此方法,则无法确定异常是由删除作者引起的,而不是由无关的东西引起的
  • 如果作者是书籍以外的其他实体的引用,则不能告诉用户必须删除书籍。它可以是引用作者的任何其他实体

请注意,对于第一种方法,如果抛出异常的目标是能够在表示层中发现它(而不是简单地显示通用错误消息),我将使用更具体的异常,例如BookStillReferencesAuthorException. 异常会更清楚,并且您不会有捕获与仍在引用作者的书籍无关的 IllegalArgumentException 的风险。

于 2012-08-10T20:20:01.400 回答