使用Mongock迁移含DBRef字段的实体时DBRef丢失,该如何解决?
解决Mongock迁移中DBRef字段丢失的问题
问题原因
你遇到的DBRef丢失问题,大概率是Spring Data MongoDB的懒加载机制导致的:默认情况下@DBRef是懒加载的,查询出的Asset对象中createdBy字段是代理对象而非实际的DBRef引用。当你修改字段后调用save(),框架无法正确将代理对象序列化为DBRef,导致原有的DBRef被替换成普通对象或者直接丢失。
另外,直接加载整个实体再保存的方式,容易触发不必要的对象序列化,破坏原有的DBRef结构。
解决方案
方案1:强制加载DBRef关联对象
修改查询逻辑,强制加载createdBy字段,避免懒加载代理:
Query query = new Query(); List<Criteria> criteriaList = new ArrayList<>(); criteriaList.add(Criteria.where("created").exists(false)); criteriaList.add(Criteria.where("updated").exists(false)); query.addCriteria(new Criteria().orOperator(criteriaList.toArray(new Criteria[0]))); // 强制加载createdBy这个DBRef字段,避免懒加载代理 query.fetch("createdBy"); List<Asset> results = mongoTemplate.find(query, Asset.class); results.forEach(asset -> { asset.setCreated(asset.getCreatedBy().getCreated()); mongoTemplate.save(asset); });
同时确保实体类的createdBy注解显式关闭懒加载:
@DBRef(lazy = false) private User createdBy;
方案2:使用数据库层面的更新操作(推荐)
避免加载整个实体,直接用聚合管道在数据库中修改目标字段,完全不触碰DBRef字段,从根源上避免问题:
Query query = new Query(); List<Criteria> criteriaList = new ArrayList<>(); criteriaList.add(Criteria.where("created").exists(false)); criteriaList.add(Criteria.where("updated").exists(false)); query.addCriteria(new Criteria().orOperator(criteriaList.toArray(new Criteria[0]))); // 使用聚合管道更新,直接关联user集合获取created字段 Aggregation aggregation = Aggregation.newAggregation( Aggregation.match(query.getCriteria()), // 关联user集合,通过DBRef的_id匹配 Aggregation.lookup( "user", // 关联的集合名 "createdBy.$id", // Asset中DBRef的_id字段 "_id", // user集合的主键 "createdByInfo" // 临时存储关联结果的字段名 ), Aggregation.unwind("$createdByInfo"), // 展开数组(lookup返回数组) // 设置created字段为关联对象的created值 Aggregation.addFields().addFieldWithValue("created", "$createdByInfo.created").build(), // 将更新后的文档写回asset集合(MongoDB 4.2+支持) Aggregation.merge(MergeOperation.builder().intoCollection("asset").build()) ); mongoTemplate.aggregate(aggregation, "asset", Asset.class);
这种方式效率更高,且不会影响原有的DBRef结构,适合批量迁移场景。
方案3:检查MongoConverter配置
如果上述方案无效,检查你的MongoConverter是否正确配置了DBRef的序列化逻辑。确保没有自定义的Converter覆盖了默认的DBRef序列化行为,导致DBRef被错误处理。
内容的提问来源于stack exchange,提问作者mukara
相关产品推荐
相关产品推荐

