JPA复合键场景下BookPublisher的JSON传参报错问题
解决JPA复合键关联实体新增时的null关联错误
我之前也遇到过类似的问题,核心原因是使用@MapsId时,JPA需要从关联的Book和Publisher实体中获取ID来填充复合键字段,而你的请求中这些关联属性要么没被正确反序列化,要么实体配置有遗漏。下面一步步给你解决思路:
1. 先检查@MapsId的配置是否匹配复合键字段
首先确保BookPublisher实体中@MapsId的参数和BookPublisherID中的字段名完全一致,这是最容易踩的坑。正确的实体配置应该是这样的:
// 复合键类 @Embeddable public class BookPublisherID implements Serializable { private Long bookID; private Long publisherID; // 必须有无参构造器 public BookPublisherID() {} // 带参构造器、getter/setter // 必须重写equals和hashCode(基于bookID和publisherID) @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; BookPublisherID that = (BookPublisherID) o; return Objects.equals(bookID, that.bookID) && Objects.equals(publisherID, that.publisherID); } @Override public int hashCode() { return Objects.hash(bookID, publisherID); } } // 关联实体类 @Entity public class BookPublisher { @EmbeddedId private BookPublisherID id; @ManyToOne @MapsId("bookID") // 这里要严格对应BookPublisherID中的bookID字段 private Book book; @ManyToOne @MapsId("publisherID") // 对应BookPublisherID中的publisherID字段 private Publisher publisher; // 其他字段、构造器、getter/setter }
2. 调整JSON请求&序列化配置
你的JSON格式本身没问题,但Jackson默认不会自动把{"id":1}这样的结构反序列化为完整的Book实体引用。可以通过两种方式解决:
方式一:配置Jackson支持Hibernate关联反序列化
在Spring Boot中添加Jackson的Hibernate模块,让它能识别关联实体的ID引用:
@Configuration public class JacksonConfig { @Bean public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() { return new Jackson2ObjectMapperBuilder() .modules(new Hibernate5Module()); // 引入Hibernate模块 } }
配置后,你原来的JSON请求就能被正确反序列化,book和publisher属性不会为null。
方式二:简化JSON,在服务层手动关联实体
如果不想改序列化配置,可以把JSON简化成只传复合键:
{ "id": { "bookID":1, "publisherID":1 } }
然后在Service层中,根据ID查询对应的Book和Publisher实例,手动设置到BookPublisher对象中:
@Service public class BookPublisherService { @Autowired private BookRepository bookRepo; @Autowired private PublisherRepository publisherRepo; @Autowired private BookPublisherRepository bookPublisherRepo; public BookPublisher createBookPublisher(BookPublisher bookPublisher) { // 查询关联实体 Book book = bookRepo.findById(bookPublisher.getId().getBookID()) .orElseThrow(() -> new RuntimeException("Book不存在")); Publisher publisher = publisherRepo.findById(bookPublisher.getId().getPublisherID()) .orElseThrow(() -> new RuntimeException("Publisher不存在")); // 设置关联属性 bookPublisher.setBook(book); bookPublisher.setPublisher(publisher); return bookPublisherRepo.save(bookPublisher); } }
3. 检查关联实体的一对多配置
最后确认Book和Publisher中的一对多关联是否正确指向BookPublisher:
@Entity public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @OneToMany(mappedBy = "book", cascade = CascadeType.ALL, orphanRemoval = true) private List<BookPublisher> bookPublishers = new ArrayList<>(); // 其他字段、getter/setter } @Entity public class Publisher { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @OneToMany(mappedBy = "publisher", cascade = CascadeType.ALL, orphanRemoval = true) private List<BookPublisher> bookPublishers = new ArrayList<>(); // 其他字段、getter/setter }
按照上面的步骤调整后,应该就能解决那个null关联的错误了。
内容的提问来源于stack exchange,提问作者Gary
相关产品推荐
相关产品推荐

