【问题标题】:Dealing with EntityNotFoundException处理 EntityNotFoundException
【发布时间】:2021-07-22 13:36:36
【问题描述】:

我正在创建简单的 REST API。我想通过 post 方法创建一个对象。对象包含其他对象。当我想发布它时,我收到了EntityNotFoundException,它在嵌套对象不存在时抛出。

我要发布的对象的代码:

@Entity
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
    private String title;

    @ManyToOne
    private Author author;

    @Id
    @Column(unique = true)
    private String isbn;
}

该对象的服务:

@Service
@RequiredArgsConstructor
public class BookServiceImpl implements BookService {
    private final BookRepository bookRepository;
    private final AuthorRepository authorRepository;

    @Override
    public Book save(Book book) {

        try {
            Author byId = authorRepository.getById(book.getAuthor().getId());
        } catch (EntityNotFoundException e) {
            authorRepository.save(book.getAuthor());
        }

        return bookRepository.save(book);
    }
}

使用 post 方法后出现此错误:

javax.persistence.EntityNotFoundException: Unable to find com.jakubkolacz.qualificationTask.domain.dao.Author with id 0
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$JpaEntityNotFoundDelegate.handleEntityNotFound(EntityManagerFactoryBuilderImpl.java:163) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:216) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]

我认为使用 try catch 来检查对象是否存在,并在必要时保存作者会有所帮助,但它没有。 我的问题是我应该在哪里添加一些代码来解决问题。我明白为什么会这样,但不知道如何解决。必要的是我不能创建手动添加作者的服务,只有在添加新书时才需要将它们添加到 repo。

【问题讨论】:

  • 您需要使用级联插入。例如在这里解释:Hibernate: How to insert OnetoMany children by cascade
  • 除了@Piotr 的提示:try/catch 可能需要更多的事务处理,如您所愿。
  • 所以我只需要将它添加到我的代码中:@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST) ?

标签: java spring rest jpa


【解决方案1】:

问题是保存操作没有被级联到作者对象。您应该在 ManyToOne 注释中添加级联类型:

@ManyToOne(cascade = CascadeType.ALL)

【讨论】:

    【解决方案2】:

    Spring 中的异常处理

    • 如果您特别想知道如何在 Spring 中处理异常,那么我强烈推荐 THIS 教程。

    实体创建

    • 首先我想指出您的实体创建的两个小问题。

    1)@ManyToOne : 虽然没有必要,但我总是喜欢用@JoinColumn 注释来注释多对一关系。它只是作为一个简单友好的视觉提醒(假设您的关系是双向的)这一方是关系的所有者(具有外键)

    2)@Id : 就目前而言,JPA 提供者(假设休眠)假定开发人员正在负责为 id 字段分配唯一标识符。当然,在处理旧的遗留数据库时,这有时是必要的。但是,如果您不处理旧数据库,我建议您删除 @Column(unique = true)String 值以替换它们:

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long isbn;
    
    • @GeneratedValue 将允许系统自动为 isb 字段生成一个值。
    • strategy = GenerationType.IDENTITY 告诉底层数据库以特定于关系数据库的方式处理唯一性和自动递增。
    • Long 而不是 String,因为它可以容纳更多的字节数。

    服务实现

    • 关于 BookServiceImpl 类,我有几句话要说,但首先,用BookService 实现接口做得很好,大多数人忘记对接口进行编程。

    1) 单一职责

    • 您同时使用 BookRepository 和 AuthorRepository,这当然没问题(如果它有效,它就有效)。但是,继续前进,您应该担心不要向一个类添加太多依赖项。如果这样做,您将破坏Single Responsibility principle,这会使代码更难测试和重构。

    2) 尝试并抓住

    • try catch 块中的代码有点混乱,尤其是因为您没有显示Author 实体类。但是,我假设你的逻辑是这样的:if the author does not exist, save the author. Lastly save and return the book。现在您认为处理 catch 块中的异常是正确的。然而,这里有很多问题要问,只有很少的代码可以继续。

    我的总体建议

    1) 分解这个方法: 这个方法试图同时做三件事。创建一种保存图书的方法,一种用于查找作者的方法,一种用于保存作者的方法。这将允许更多的代码重用向前发展。

    2) 阅读 CascadeType : 特别是 PERSIST,这可能会帮助您解决问题。此外,请研究多对多关系,因为多本书有多个作者并不少见。

    【讨论】:

      猜你喜欢
      • 2018-08-31
      • 1970-01-01
      • 1970-01-01
      • 2013-08-16
      • 2014-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多