Spring Data JPA:如何按子实体筛选并返回含选中子实体的父实体
解决方案
1. 先对查询结果按城市分组
你当前拿到的是List<SchoolEntity>,其中可能有多个学校属于同一个城市,首先需要把这些学校按所属城市分组,避免后续出现重复的城市条目:
@GetMapping("/from-school") public List<City> fromSchool2() { List<SchoolEntity> schoolEntities = schoolEntityRepository.findByNameContaining("Java"); // 按所属城市分组,得到 城市 -> 该城市下符合条件的学校列表 Map<CityEntity, List<SchoolEntity>> cityToSchoolsMap = schoolEntities.stream() .collect(Collectors.groupingBy(SchoolEntity::getCity)); // 处理每个城市,替换原有的schools列表为筛选后的列表 List<CityEntity> processedCities = new ArrayList<>(); for (Map.Entry<CityEntity, List<SchoolEntity>> entry : cityToSchoolsMap.entrySet()) { CityEntity city = entry.getKey(); // 替换原实体的全量schools为筛选后的列表 city.setSchools(entry.getValue()); processedCities.add(city); } // 用MapStruct映射成City DTO return CityEntityMapper.INSTANCE.map(processedCities); }
2. 调整MapStruct映射器
你的原MapStruct接口只支持从List<SchoolEntity>映射,现在需要改成支持从List<CityEntity>映射到List<City>,同时处理嵌套的School DTO:
先补全你的DTO定义(假设未完成):
// City DTO public class City { private int id; private String name; private String postcode; private List<School> schools; // getter/setter } // School DTO public class School { private int id; private String name; // getter/setter }
修改MapStruct接口:
@Mapper public interface CityEntityMapper { CityEntityMapper INSTANCE = Mappers.getMapper(CityEntityMapper.class); // 单个CityEntity转City City map(CityEntity cityEntity); // 批量转换CityEntity列表 List<City> map(List<CityEntity> cityEntities); // 单个SchoolEntity转School School map(SchoolEntity schoolEntity); // 批量转换SchoolEntity列表 List<School> map(List<SchoolEntity> schoolEntities); }
3. 优化:直接从CityEntity查询(更高效)
上面的方法需要先查学校再分组,其实可以直接用JPQL从CityEntity入手,关联筛选符合条件的学校,一步拿到结果,避免内存分组和N+1查询问题:
在CityEntityRepository中添加查询方法:
public interface CityEntityRepository extends JpaRepository<CityEntity, Integer> { @Query("SELECT c FROM CityEntity c JOIN FETCH c.schools s WHERE s.name LIKE %:name%") List<CityEntity> findBySchoolsNameContaining(@Param("name") String name); }
控制器直接调用:
@GetMapping("/from-school") public List<City> fromSchool2() { List<CityEntity> cityEntities = cityEntityRepository.findBySchoolsNameContaining("Java"); return CityEntityMapper.INSTANCE.map(cityEntities); }
内容的提问来源于stack exchange,提问作者tweetysat
相关产品推荐
相关产品推荐

