Spring Boot+MongoDB关联对象持久化问题:关联对象为Null
Spring Boot整合MongoDB实现关联对象持久化问题解决
问题原因分析
- 字段映射不匹配:请求JSON中的
address字段,与Student实体类里的studentAddress字段未做映射,导致反序列化时该字段为null。 - 缺少无参构造方法:实体类使用
@AllArgsConstructor覆盖了默认无参构造,Spring Data MongoDB和Jackson无法正常实例化对象,引发属性初始化异常。 - 关联对象未提前持久化:
@DocumentReference是MongoDB的引用式关联,要求关联的子文档必须先被持久化生成ID,才能在父文档中保存引用。直接保存StudentClass时,内部的Student和StudentAddress未被单独保存,无法生成有效引用ID,因此返回null。
解决方案
步骤1:修正实体类
调整Student类,修复字段映射和构造方法
@Data @NoArgsConstructor // 添加无参构造 @AllArgsConstructor @Document public class Student { @Id private ObjectId id; @Indexed(unique = true) private Long studentId; private String studentName; private int age; private int rollno; @JsonProperty("address") // 映射请求中的address字段 @DocumentReference private StudentAddress studentAddress; }
调整StudentAddress和StudentClass,添加无参构造
@Data @NoArgsConstructor @AllArgsConstructor @Document public class StudentAddress { @Id private ObjectId id; private String hno; private String town; private Long pinCode; private String city; }
@Data @NoArgsConstructor @AllArgsConstructor @Document public class StudentClass { @Id private ObjectId id; private Long classNo; private String className; @DocumentReference private List<Student> student; }
步骤2:修改Service层保存逻辑,分层持久化关联对象
实现StudentClassService,确保先保存StudentAddress,再保存Student,最后保存StudentClass:
@Service @RequiredArgsConstructor public class StudentClassService { private final StudentClassRepository studentClassRepository; private final StudentRepository studentRepository; private final StudentAddressRepository studentAddressRepository; public StudentClass saveClassWithStudent(StudentClass studentClass) { List<Student> savedStudents = new ArrayList<>(); // 遍历处理每个Student的关联对象 for (Student student : studentClass.getStudent()) { StudentAddress address = student.getStudentAddress(); if (address != null) { // 先保存StudentAddress StudentAddress savedAddress = studentAddressRepository.save(address); student.setStudentAddress(savedAddress); } // 再保存Student Student savedStudent = studentRepository.save(student); savedStudents.add(savedStudent); } // 将持久化后的Student列表绑定到StudentClass studentClass.setStudent(savedStudents); // 最后保存StudentClass return studentClassRepository.save(studentClass); } public List<StudentClass> getAllClasses() { return studentClassRepository.findAll(); } }
步骤3:可选:嵌入式文档替代引用式关联
如果希望返回结果与请求格式完全一致(直接嵌入关联对象而非仅ID引用),可以改用嵌入式文档结构,去掉@DocumentReference和子实体的@Document注解:
// StudentAddress作为内嵌类,无需@Document @Data @NoArgsConstructor @AllArgsConstructor public class StudentAddress { private String hno; private String town; private Long pinCode; private String city; } // Student作为内嵌类,无需@Document @Data @NoArgsConstructor @AllArgsConstructor public class Student { private Long studentId; private String studentName; private int age; private int rollno; @JsonProperty("address") private StudentAddress studentAddress; } // StudentClass直接内嵌Student列表 @Data @NoArgsConstructor @AllArgsConstructor @Document public class StudentClass { @Id private ObjectId id; private Long classNo; private String className; private List<Student> student; }
这种方式下,直接保存StudentClass即可,所有数据会嵌入到同一个MongoDB文档中,返回结果与请求格式完全匹配。
内容的提问来源于stack exchange,提问作者Srikar Sharma
相关产品推荐
相关产品推荐

