Spring Data MongoDB使用DBRef查询关联文档返回null问题求解
问题核心原因
- CategoryEntity仅自定义了带参构造函数,未提供无参构造函数,Spring Data MongoDB 映射关联实体时必须依赖无参构造完成实例化,缺失会直接导致category字段映射为null
@DBRef(lazy = true)开启了懒加载,你在实体转换时没有触发懒加载初始化逻辑,也没有在事务环境下保持持久化上下文打开,即使映射成功也无法拿到代理对象里的真实数据
解决方案
方案1:使用即时加载(推荐,适配你的业务需求)
步骤1:给CategoryEntity补充无参构造函数
你可以直接加Lombok的@NoArgsConstructor注解,或者手动编写无参构造:
@Data @Document(collection = "categories") public class CategoryEntity implements Serializable { private static final long serialVersionUID = -636356399519451958L; @MongoId(value = FieldType.STRING) private String id; @Field("name") private String name; @Field("desc") private String desc; // 补充无参构造 public CategoryEntity() { } public CategoryEntity(String id) { super(); this.id = id; } // getters and setters }
步骤2:关闭@DBRef的懒加载配置
将ProductEntity中category字段的@DBRef(lazy = true)改为默认即时加载:
@Field("category") @DBRef private CategoryEntity category;
改完后调用productRepo.findAll()时,Spring Data MongoDB会自动关联查询categories集合的对应文档,直接返回完整的category实体数据,你原有的业务转换逻辑不需要做任何修改即可得到期望的输出格式。
方案2:保留懒加载
如果你确实需要保留懒加载特性,需要给getProducts()方法添加@Transactional注解保证持久化上下文在转换实体时处于打开状态,同时在拷贝属性前主动触发懒加载初始化:
@Transactional public List<ProductModel> getProducts() { List<ProductEntity> entities = productRepo.findAll(); return entities.stream().map(entity -> { ProductModel product = new ProductModel(); BeanUtils.copyProperties(entity, product); if (Objects.nonNull(entity.getCategory())) { // 主动触发懒加载初始化 entity.getCategory().getName(); BeanUtils.copyProperties(entity.getCategory(), product.getCategory()); } return product; }).collect(Collectors.toList()); }
注意此方案会产生N+1查询问题,查询N条Product会额外触发N次Category的查询,性能远低于方案1。
内容的提问来源于stack exchange,提问作者Ravi S.
相关产品推荐
相关产品推荐

