问题描述
我的产品中有graphql,并且禁止共享代码。我使用的是graphql-java-servlet,因为ORM使用的是MyBatis。
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-java-servlet</artifactId>
<version>9.2.0</version>
</dependency>
启用BatchLoading后,我发现graphQL DataLoader混淆了批处理请求实体的位置。同样,如果查看一下futureCacheMap也很容易,您会发现Key(Id)和Value(Entity)具有不同的ID。
调试后,我找不到在批处理加载(1000 psc)后graphQL如何解析实体的方式。因此,我决定应该进行一些订购,因此我实施了订购,但未能解决问题。
例如: 我有Parent.class,里面有孩子。
class Parent {
private Long id;
private List<Long> childsIds;
}
我有ChildDataLoader
private BatchLoader<Long,Child> buildBatchLoader() {
return list -> > CompletableFuture.supplyAsync(() -> childService.findByIds(list));
}
private DataLoader<Long,Child> buildDataLoader(BatchLoader batchLoader) {
DataLoaderOptions options = DataLoaderOptions.newOptions();
options.setMaxBatchSize(1000);
return new DataLoader<Long,Child>(batchLoader,options);
}
}
我有ChildsFetcher,在这里我叫DataLoader.loadMany()
public class ChildsFetcher implements DataFetcher<CompletableFuture<List<Child>>>{
private static final String PK_FIELD_NAME = "childsIds";
@Override
public CompletableFuture<List<LoadDeFinitionDTO>> get(DataFetchingEnvironment environment) {
GraphQLContext context = environment.getContext();
DataLoaderRegistry DataLoaderRegistry = context.getDataLoaderRegistry().orElseThrow(
() -> new Dalexception("there was no DataLoaderRegistry in context",Response.Status.INTERNAL_SERVER_ERROR)
);
List<Long> childsIds = getParentFieldValue(environment,PK_FIELD_NAME,List.class);
DataLoader<Long,Child> childDataLoader = DataLoaderRegistry.getDataLoader("childDataLoader");
return childDataLoader.loadMany(childsIds)
}
}
例如,我有2个父母,每个父母有3个孩子。
parents: [
{
"id": 1
"childIds": {1,3,5}
},{
"id": 2
"childIds": {2,4,6}
}
]
由于在fetcher中,我将有2个请求:
-
childDataLoader.loadMany({1,5})
-
childDataLoader.loadMany({2,6})
在DataLoader中,它只会是一个(如预期的那样),但请查看ID的顺序(我无法控制它):
childService.findByIds({1,5,2,6})
在输出中,我将收到:
"data": {
"parents": [
{
"id": 1,"childs": [
{
"id": 1,},{
"id": 2,{
"id": 3,}
},{
"id": 2,"childs": [
{
"id": 4,{
"id": 5,{
"id": 6,}
}
]
}
]
}
解决方法
答案的顺序必须与请求的顺序相同, 如果ORM对sql响应进行了排序,请在从ORM获得响应后,将其重新放入DataLoader中,例如:
private BatchLoader<Long,Child> buildBatchLoader() {
return list -> CompletableFuture.supplyAsync(() ->
childService.findByIds(list).stream()
.sorted(Comparator.comparingLong(entity ->
list.indexOf(entity.getId())))
.collect(Collectors.toList()));
};