Spring Data JPA新增File时外键customer_id为null如何解决
问题根因
customer_id写入为null是三个问题共同导致的:
FileDTO定义的字段是完整Customer对象,和接口传入的整数类型customer_id参数不匹配,框架反序列化请求时直接忽略了这个未匹配的字段,根本没读到传入的ID值- 转换逻辑只做了同名字段直接拷贝,没有根据传入的客户ID关联查询对应的Customer实体赋值给File对象,JPA拿不到关联实体自然没法写入外键
- 现有代码存在多处语法错误、Java命名规范违规问题,会直接阻断正常逻辑运行
修复步骤
1. 修正实体类命名与字段映射
Java实体属性严格遵循小驼峰命名规范,修正原代码中大写开头的属性名,避免框架映射失败:
// Customer实体修正后 @NoArgsConstructor @AllArgsConstructor @Data @Builder @Entity @Table(name = "customer") public class Customer { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; // 修正原大写开头的属性名,和数据库字段customernamesurname对齐 private String customernamesurname; private String email; // 修正原大写开头的集合属性名 @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, orphanRemoval = true) private List<File> files = new ArrayList<>(); }
// File实体修正后 @NoArgsConstructor @AllArgsConstructor @Data @Builder @Entity @Table(name = "file") public class File implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String fileName; // 修正原大写开头的关联属性名 @ManyToOne @JoinColumn(name="customer_id") private Customer customer; }
2. 调整FileDTO字段,直接接收整数类型客户ID
去掉DTO里多余的Customer对象字段,直接用Integer类型的customerId接收前端传参,和需求对齐:
@Data public class FileDTO { private String fileName; private Integer customerId; }
如果要继续用下划线格式的请求参数,不用给每个字段加@JsonProperty,直接在application.yml里加全局配置即可自动映射file_name->fileName、customer_id->customerId:
spring: jackson: property-naming-strategy: SNAKE_CASE
*同时删掉CustomerDTO里多余的private Customer customer;字段,这个字段没有任何业务作用。
3. 重写FileMapper转换逻辑
不要用静态方法硬写转换,把Mapper交给Spring管理,注入CustomerRepository,转换时根据传入的ID查询关联的客户实体再赋值:
@Component public class FileMapper { @Resource private CustomerRepository customerRepository; public FileDTO toDto(File file){ FileDTO fileDTO = new FileDTO(); fileDTO.setFileName(file.getFileName()); // 出参直接返回关联的客户ID即可 fileDTO.setCustomerId(file.getCustomer().getId()); return fileDTO; } public File toEntity(FileDTO fileDTO){ File file = new File(); file.setFileName(fileDTO.getFileName()); if (fileDTO.getCustomerId() != null) { // 根据ID查询关联客户,ID不存在直接抛参数错误 Customer customer = customerRepository.findById(fileDTO.getCustomerId()) .orElseThrow(() -> new IllegalArgumentException("传入的客户ID不存在")); file.setCustomer(customer); } return file; } }
4. 修复现有代码的语法错误
- 修正CustomerMapper里的笔误:原代码
customerDTO.setEmailcustomer.getEmail())缺少方法调用点,改成customerDTO.setEmail(customer.getEmail()) - 修正Controller里的参数名错误:原代码参数定义为大写开头的
File,和后续调用的小写file变量名不匹配,会直接编译失败,修正后代码如下:
@RestController public class FileController { @Resource private FileService fileService; @Resource private FileMapper fileMapper; @PostMapping(path = "/addFile") public boolean addFile(@RequestBody FileDTO fileDTO) { return fileService.addFile(fileMapper.toEntity(fileDTO)); } }
验证效果
修复完成后传入原请求体即可正常写入:
{ "file_name": "Test", "customer_id": 2 }
执行流程为:框架自动把请求参数映射到FileDTO,Mapper转换时查询到ID为2的客户实体赋值给File的关联属性,JPA保存时会自动提取关联实体的ID写入customer_id外键字段,不会再出现null值。
内容的提问来源于stack exchange,提问作者RohanRider
相关产品推荐
相关产品推荐

