如何让Spring-data-mongo忽略List<Entity>中的空@DBRef?
解决Spring Data Mongo中List忽略缺失引用的问题
要实现Morphia中@Reference(ignoreMissing = true)的效果——自动跳过列表中无法加载的DBRef、避免出现null元素,需要同时处理批量DBRef获取和单个DBRef读取两种场景,并且在集合转换阶段过滤null实体。以下是具体实现方案:
1. 自定义DbRefResolver,覆盖核心读取方法
Spring Data Mongo在处理单元素DBRef列表时会调用readRef,多元素时调用bulkFetch,因此需要同时重写这两个方法,确保缺失的引用返回null或被过滤:
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver; import org.springframework.data.mongodb.core.convert.MongoDatabaseFactory; import org.springframework.lang.NonNull; import org.bson.Document; import com.mongodb.DBRef; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; public class IgnoreMissingDbRefResolver extends DefaultDbRefResolver { public IgnoreMissingDbRefResolver(MongoDatabaseFactory mongoDbFactory) { super(mongoDbFactory); } // 批量获取DBRef时,过滤掉不存在的文档 @Override @NonNull public List<Document> bulkFetch(@NonNull List<DBRef> refs) { return super.bulkFetch(refs) .stream() .filter(Objects::nonNull) .collect(Collectors.toList()); } // 读取单个DBRef时,找不到文档返回null(后续集合转换时过滤) @Override public Document readRef(@NonNull DBRef ref) { try { return super.readRef(ref); } catch (Exception e) { // 捕获文档不存在的异常,返回null return null; } } }
2. 自定义MappingMongoConverter,过滤集合中的null实体
默认情况下,Spring会将null文档转换为null实体并保留在列表中,因此需要重写集合读取逻辑,自动移除null元素:
import org.springframework.data.mongodb.core.convert.MappingMongoConverter; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.lang.NonNull; import org.bson.Document; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; public class IgnoreNullElementsMappingConverter extends MappingMongoConverter { public IgnoreNullElementsMappingConverter(IgnoreMissingDbRefResolver dbRefResolver, MongoMappingContext mappingContext) { super(dbRefResolver, mappingContext); } @Override protected <T> List<T> readCollection(@NonNull Class<T> targetType, @NonNull List<Document> source) { return super.readCollection(targetType, source) .stream() .filter(Objects::nonNull) .collect(Collectors.toList()); } }
3. 配置Bean替换默认组件
在Spring Boot配置类中注册自定义的解析器和转换器,让全局生效:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.convert.MongoConverter; import org.springframework.data.mongodb.core.convert.SimpleMongoClientDatabaseFactory; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import com.mongodb.client.MongoClient; @Configuration public class MongoConfig { @Bean public MongoConverter mongoConverter(MongoClient mongoClient, MongoMappingContext mappingContext) { // 替换为你的数据库名称 SimpleMongoClientDatabaseFactory dbFactory = new SimpleMongoClientDatabaseFactory(mongoClient, "your-database-name"); IgnoreMissingDbRefResolver dbRefResolver = new IgnoreMissingDbRefResolver(dbFactory); IgnoreNullElementsMappingConverter converter = new IgnoreNullElementsMappingConverter(dbRefResolver, mappingContext); converter.setTypeMapper(getDefaultMongoTypeMapper()); return converter; } @Bean public MongoTemplate mongoTemplate(MongoClient mongoClient, MongoConverter mongoConverter) { MongoTemplate template = new MongoTemplate(mongoClient, "your-database-name"); template.setConverter(mongoConverter); return template; } }
局部场景替代方案
如果不需要全局生效,也可以在实体的setter方法中手动过滤null元素:
public class Book { @DBRef private List<Author> authors; public void setAuthors(List<Author> authors) { this.authors = authors != null ? authors.stream().filter(Objects::nonNull).collect(Collectors.toList()) : null; } }
这种方式无需修改全局配置,但需要为每个涉及的实体添加过滤逻辑。
内容的提问来源于stack exchange,提问作者takanuva15
相关产品推荐
相关产品推荐

