0

我有一个 Spring Boot 应用程序,它在 h2 数据库中有 2 个表:Computer和一个Processor

计算机和处理器之间存在单向、多对一的关系,因此许多计算机可以拥有一个处理器。在架构中,关系上有一个外键约束,因此不允许您删除某些计算机正在使用的处理器。

我希望能够向用户显示有用的错误消息,例如:“处理器'M1'不能被删除,因为它被计算机'MacBook,MacBook Pro'使用。 ”但是我能够成功捕获DataIntegrityViolationException此错误不包含足够的信息,我无法生成所需的错误消息。它只提到违反了定义的 foreignKeyConstraint。

因此,作为一种解决方法,当引发DataIntegrityViolationException时,我会捕获它并查询数据库以获取特定实例,为什么不能删除处理器并以这种方式生成错误消息。我可以很容易地不在模式中添加 FK 约束,只需检查服务中的数据库,以确保要删除的处理器未在数据库中的任何计算机中使用,并生成适当的错误。但是,以编程方式检查 FK 约束感觉就像是代码异味。

有没有办法让我在数据库级别使用 FK 约束并使用DataIntegrityViolationException生成有用的错误消息?

// ENTITIES
@Entity
@Table(name = "Computer", schema = "CS")
public class Computer extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "computer_id")
    @Getter
    @Setter
    private long id;
    ...
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "processor_id")
    @OnDelete(action= OnDeleteAction.NO_ACTION)
    @Getter
    @Setter
    private Processor processor;
    ...
}

@Entity
@Table(name = "Processor", schema = "CS")
public class Processor extends BaseEntity {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     @Column(name = "processor_id")
     @Getter@Setter
     private long id;
    ...
}

 // PROCESSOR_CONTROLLER
 public ResponseEntity<Void> deleteByName(@PathVariable("name")) String name) {
   try {
        processorService.deleteByName(name);
   } catch (DataIntegrityViolationException e) {
       List<String> computerList = new ArrayList<>();
       computerService.findAllByHoldName(name).forEach(computer -> computerList.add(computer.getProcessor()));
       String computersString = computersList.stream().reduce("", (res, next) -> res += next + ",");
       throw new DataIntegrityViolationException (String.format("Processor '%s' is used by Computer(s) '%s'. It cannot be deleted.", name, computersString));
   }
   return ResponseEntity.noContent().build();
}

// PROCESSOR_SERVICE
@Transactional
public void deleteByName(String name) {
    Processor existingProcessor = processorRepository.findByName(name);
    processorRepository.delete(existingProcessor);
}

提前感谢您的帮助!!

4

0 回答 0