Spring中如何利用Repository多态返回所有Animal类型数据?
问题分析与解决方案
你遇到的问题核心在于:Spring Data Repository是基于具体实体类生成代理实例的,而Animal是接口而非带@Document注解的实体类。当你注入AnimalRepository<Animal>时,Spring无法找到对应的实体映射,生成的代理不会处理任何MongoDB文档,因此调用findAll()返回空列表。
下面提供几种可行的实现方案:
方案1:将Animal改为带@Document的抽象类(推荐)
把Animal从接口改为抽象类并添加@Document注解,让Spring Data MongoDB识别它作为父实体,自动处理子类的继承关系(MongoDB会通过_class字段区分不同子类)。
调整后的代码:
@Document abstract class Animal { } @Document class Dog extends Animal { } @Document class Cat extends Animal { } // 直接定义针对Animal的Repository interface AnimalRepository extends ReactiveCrudRepository<Animal, String> { } // 原有的DogRepository、CatRepository可保留,用于单独操作对应类型 interface DogRepository extends AnimalRepository { } interface CatRepository extends AnimalRepository { }
此时注入AnimalRepository调用findAll(),会自动查询所有Dog和Cat类型的文档,返回合并后的结果。
方案2:自定义Repository实现(保留Animal为接口)
如果必须保留Animal作为接口,可以创建自定义的Repository实现,注入DogRepository和CatRepository,合并两者的查询结果:
- 定义基础Repository接口:
interface AnimalRepository extends ReactiveCrudRepository<Animal, String> { }
- 编写实现类:
class AnimalRepositoryImpl implements AnimalRepository { private final DogRepository dogRepo; private final CatRepository catRepo; // 构造注入 public AnimalRepositoryImpl(DogRepository dogRepo, CatRepository catRepo) { this.dogRepo = dogRepo; this.catRepo = catRepo; } @Override public Flux<Animal> findAll() { // 合并两个子类的查询结果 return Flux.concat(dogRepo.findAll(), catRepo.findAll()); } // 按需实现其他ReactiveCrudRepository方法,比如findById可先查Dog再查Cat @Override public Mono<Animal> findById(String id) { return dogRepo.findById(id) .switchIfEmpty(catRepo.findById(id)); } // 其余方法(如save、delete等)需根据业务需求实现 }
- 确保Spring能扫描到这个实现类,可通过
@Repository注解或配置类注册Bean。
方案3:使用MongoTemplate直接查询
无需修改现有Repository结构,直接通过MongoTemplate查询所有Animal子类的文档:
class Test { @Autowired private MongoTemplate mongoTemplate; public void getAllAnimals() { Query query = new Query(); // 通过MongoDB自动生成的_class字段匹配所有子类 query.addCriteria(Criteria.where("_class").in( Dog.class.getName(), Cat.class.getName() )); List<Animal> animals = mongoTemplate.find(query, Animal.class); } }
这种方式灵活,但需要手动维护子类列表,新增动物类型时需更新查询条件。
内容的提问来源于stack exchange,提问作者Patrick
相关产品推荐
相关产品推荐

