Spring Data REST投影问题:列表接口无法返回关联地址数据
问题分析与解决方案
你遇到的问题是Spring Data REST中集合资源的投影无法返回关联实体数据,但单个资源可以,核心原因是集合查询时的懒加载机制导致关联数据未被加载,投影无法获取到数据进行序列化。
问题原因拆解
- Spring Data REST为了性能优化,对集合类型的关联默认采用
FetchType.LAZY(懒加载),当查询persons集合时,不会主动加载关联的Address数据; - 单个资源查询时,序列化过程中调用了投影的
getAddress()方法,触发了懒加载,所以能返回地址数据; - 即使你指定了
excerptProjection或通过?projection=resumePerson参数调用集合接口,因为关联数据未被预加载,投影也无法输出这部分内容。
解决方案
推荐使用EntityGraph来显式指定集合查询时预加载关联的Address数据,既保证性能又能满足投影需求,具体步骤如下:
1. 修改PersonRepository,添加EntityGraph注解
在Repository的查询方法上添加@EntityGraph,指定要预加载的关联属性:
@RepositoryRestResource(collectionResourceRel = "persons", path = "persons", excerptProjection = ResumePerson.class) public interface PersonRepository extends PagingAndSortingRepository<Person, Long> { // 覆盖findAll方法,指定预加载address关联 @Override @EntityGraph(attributePaths = "address") Iterable<Person> findAll(); // 分页查询也要覆盖,保证分页场景下也能预加载 @Override @EntityGraph(attributePaths = "address") Page<Person> findAll(Pageable pageable); }
2. 验证效果
修改后重新启动应用,调用http://localhost:8080/project/api/persons?projection=resumePerson,就能看到返回结果中包含address数据了:
{ "_embedded" : { "persons" : [ { "firstname" : "firstname_1", "lastname" : "lastname_1", "address": [ { "rue" : "RUE_1", "code" : "CODE_1", "country" : "COUNTRY_1" } ], "_links" : { "self" : { "href" : "http://localhost:8080/si-ice/api/persons/1{?projection}", "templated" : true }, "address" : { "href" : "http://localhost:8080/si-ice/api/agents/1/address" } } } ] } }
不推荐的方案:改为EAGER加载
虽然可以把@OneToMany的fetch属性改为FetchType.EAGER来强制加载关联,但这种方式会导致所有查询(包括不需要地址的场景)都加载Address数据,严重影响集合查询的性能,因此不建议使用:
// 不推荐,性能差 @OneToMany(fetch = FetchType.EAGER) List<Address> address;
内容的提问来源于stack exchange,提问作者Dali
相关产品推荐
相关产品推荐

