Java Spring中ReactiveCosmosRepository如何返回数值型查询结果?
问题:Azure Spring Data Cosmos 查询返回数值类型失败
问题描述
使用ReactiveCosmosRepository自定义查询返回数值(如MAX、COUNT计算结果)时抛出异常,返回实体类的查询可正常运行,但返回数值的查询始终失败,尝试过Mono<Integer>、Mono<Long>、Mono<Object>等多种返回类型均无效。
仓库代码
@Repository public interface RepoCosmos extends ReactiveCosmosRepository<MyClass, String> { @Query("SELECT * FROM c WHERE c.Foo = @Foo") Mono<MyClass> get(@Param("Foo") String Foo); @Query("SELECT VALUE MAX(c.intID) FROM c WHERE NOT c.condition") Mono<?> getMaxIntID(); @Query("SELECT VALUE COUNT(1) FROM c") Mono<?> test(); }
执行代码与异常
执行代码:
Mono<?> b = RepoCosmos.getMaxIntID(); b.block();
抛出异常:
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2023-09-13 07:37:45.672 ERROR 19908 --- [ main] o.s.boot.SpringApplication : Application run failed java.lang.IllegalStateException: Failed to execute ApplicationRunner at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:785) ~[spring-boot-2.5.6.jar:2.5.6] at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:772) ~[spring-boot-2.5.6.jar:2.5.6] at org.springframework.boot.SpringApplication.run(SpringApplication.java:345) ~[spring-boot-2.5.6.jar:2.5.6] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-2.5.6.jar:2.5.6] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332) ~[spring-boot-2.5.6.jar:2.5.6] at com.careerswales.urlservice.UrlApplication.main(UrlApplication.java:13) ~[main/:na] Caused by: java.lang.IllegalArgumentException: domain should contain @Id field or field named id at com.azure.spring.data.cosmos.repository.support.CosmosEntityInformation.getIdField(CosmosEntityInformation.java:317) ~[azure-spring-data-cosmos-3.17.0.jar:3.17.0] Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: Assembly trace from producer [reactor.core.publisher.FluxMapFuseable] : reactor.core.publisher.Flux.map(Flux.java:6273) com.azure.spring.data.cosmos.core.ReactiveCosmosTemplate.runQuery(ReactiveCosmosTemplate.java:660) Error has been observed at the following site(s): *________Flux.map ⇢ at com.azure.spring.data.cosmos.core.ReactiveCosmosTemplate.runQuery(ReactiveCosmosTemplate.java:660) *__Flux.usingWhen ⇢ at org.springframework.data.repository.core.support.RepositoryMethodInvoker$ReactiveInvocationListenerDecorator.decorate(RepositoryMethodInvoker.java:242) |_ Mono.from ⇢ at org.springframework.data.repository.util.ReactiveWrapperConverters$PublisherToMonoConverter.convert(ReactiveWrapperConverters.java:564)
解决方案
方法1:使用ReactiveCosmosTemplate直接执行查询
绕开Repository对实体类型的校验,直接注入ReactiveCosmosTemplate手动执行查询并转换结果:
@Autowired private ReactiveCosmosTemplate cosmosTemplate; public Mono<Integer> getMaxIntID() { String query = "SELECT VALUE MAX(c.intID) FROM c WHERE NOT c.condition"; return cosmosTemplate.query(query, new CosmosQueryRequestOptions(), Integer.class) .single(); } public Mono<Long> testCount() { String query = "SELECT VALUE COUNT(1) FROM c"; return cosmosTemplate.query(query, new CosmosQueryRequestOptions(), Long.class) .single(); }
方法2:创建带@Id的包装类接收结果
如果坚持使用Repository接口,需要定义一个包含@Id字段的包装类来适配查询结果:
public class NumericResult { @Id private String id; // 可设固定值,仅用于框架校验 private Number value; // 构造器、Getter、Setter }
修改Repository方法,将查询结果映射到包装类:
@Query("SELECT {\"id\": \"max-id\", \"value\": MAX(c.intID)} FROM c WHERE NOT c.condition") Mono<NumericResult> getMaxIntID(); @Query("SELECT {\"id\": \"count-id\", \"value\": COUNT(1)} FROM c") Mono<NumericResult> test();
后续从NumericResult实例中取出value即可获得目标数值。
问题核心原因
Azure Spring Data Cosmos的Repository默认期望查询返回带@Id字段的实体类,当返回原始数值类型时,框架会尝试将结果映射为实体类,因找不到@Id字段触发异常。通过Template直接执行或用包装类适配,即可规避该校验逻辑。
内容的提问来源于stack exchange,提问作者Vhagar
相关产品推荐
相关产品推荐

