我有一个 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);
}
提前感谢您的帮助!!