我的生产中有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。
经过调试,我没有找到graphQL如何在batchLoading(1000 psc)之后解析Entities的方式。所以我决定我应该进行一些排序,所以我实现了它,但它并没有解决问题。
例如: 我有 Parent.class,里面有 Childs。
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 个 parent ,每个 parent 有 3 个 child 。
parents: [
{
"id": 1
"childIds": {1,3,5}
},
{
"id": 2
"childIds": {2,4,6}
}
]
作为 fetcher 的结果,我将有 2 个请求:
childDataLoader.loadMany({1,3,5})
childDataLoader.loadMany({2,4,6})
在 Dataloader 中它将只有一个(如预期的那样),但请查看 ID 的顺序(我无法控制它):
childService.findByIds({1,3,5,2,4,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()));
};
关于java - DataLoader批量加载bug(MyBatis、JavaEE),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63630507/