You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,合并两者的查询结果:

  1. 定义基础Repository接口:
interface AnimalRepository extends ReactiveCrudRepository<Animal, String> { }
  1. 编写实现类:
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等)需根据业务需求实现
}
  1. 确保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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 16:48:58