You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DGS Framework:如何向数据获取器传递额外数据?

问题场景

我有如下@DgsQuery方法:

@DgsQuery
public List<Sensor> sensors(DgsDataFetchingEnvironment dfe) {
     
    SensorType sensorType = SensorType.newBuilder()
            .id(UUID.randomUUID().toString())
            .build();
    

    Sensor sensor = new Sensor();
    sensor.setId(UUID.randomUUID().toString());
    sensor.setName("foo");
    sensor.setSensorType(sensorType);

    return Arrays.asList(sensor);
}

以及对应的@DgsData数据获取器:

@DgsData(parentType = DgsConstants.SENSOR.TYPE_NAME, field = DgsConstants.SENSOR.SensorType)
public CompletableFuture<SensorType> sensorType(DgsDataFetchingEnvironment dfe) {
    Sensor sensor = dfe.getSource();
    UUID sensorTypeId = UUID.fromString(sensor.getSensorType().getId());

    // fetch sensorType by ID from DB, map to generated class and return
    LOGGER.info("Would now fetch sensorType with ID {} via RPC or whatever you want ;)", sensorTypeId);

    return null;
}

现在需要在数据获取器中访问@DgsQuery方法里初始化的额外数据/对象(比如从数据库加载的Entity),但目前只能通过dfe.getSource()拿到Sensor对象,无法获取其他已加载的额外数据,该如何实现?


解决方案

1. 扩展DTO对象,添加内部字段存储额外数据

如果允许修改Sensor这类DTO,可以添加一个仅用于内部传递的字段(无需在GraphQL Schema中暴露),直接存储额外数据。

修改@DgsQuery方法:

@DgsQuery
public List<Sensor> sensors(DgsDataFetchingEnvironment dfe) {
    // 从数据库加载目标Entity
    SensorEntity sensorEntity = sensorRepository.findById(someId);

    SensorType sensorType = SensorType.newBuilder()
            .id(sensorEntity.getSensorTypeId().toString())
            .build();
    
    Sensor sensor = new Sensor();
    sensor.setId(sensorEntity.getId().toString());
    sensor.setName(sensorEntity.getName());
    sensor.setSensorType(sensorType);
    // 将额外Entity存入DTO的内部字段
    sensor.setSensorEntity(sensorEntity);

    return Arrays.asList(sensor);
}

在数据获取器中直接读取:

@DgsData(parentType = DgsConstants.SENSOR.TYPE_NAME, field = DgsConstants.SENSOR.SensorType)
public CompletableFuture<SensorType> sensorType(DgsDataFetchingEnvironment dfe) {
    Sensor sensor = dfe.getSource();
    // 获取额外存储的Entity数据
    SensorEntity sensorEntity = sensor.getSensorEntity();
    
    // 直接使用Entity数据构建结果,无需重复查库
    SensorType sensorType = SensorType.newBuilder()
            .id(sensorEntity.getSensorTypeId().toString())
            .name(sensorEntity.getSensorTypeName())
            .build();

    return CompletableFuture.completedFuture(sensorType);
}

2. 利用DgsDataFetchingEnvironment上下文存储

通过DgsDataFetchingEnvironment的setContext()和getContext()方法,在Query阶段将额外数据存入上下文,后续数据获取器从上下文读取。

方式1:用Map存储多数据

修改@DgsQuery方法:

@DgsQuery
public List<Sensor> sensors(DgsDataFetchingEnvironment dfe) {
    SensorEntity sensorEntity = sensorRepository.findById(someId);

    // 用Map存储额外数据,以Sensor ID作为键区分多对象
    Map<String, Object> contextMap = new HashMap<>();
    contextMap.put("sensorEntity_" + sensorEntity.getId(), sensorEntity);
    dfe.setContext(contextMap);

    SensorType sensorType = SensorType.newBuilder()
            .id(sensorEntity.getSensorTypeId().toString())
            .build();
    
    Sensor sensor = new Sensor();
    sensor.setId(sensorEntity.getId().toString());
    sensor.setName(sensorEntity.getName());
    sensor.setSensorType(sensorType);

    return Arrays.asList(sensor);
}

数据获取器中读取:

@DgsData(parentType = DgsConstants.SENSOR.TYPE_NAME, field = DgsConstants.SENSOR.SensorType)
public CompletableFuture<SensorType> sensorType(DgsDataFetchingEnvironment dfe) {
    Sensor sensor = dfe.getSource();
    Map<String, Object> contextMap = (Map<String, Object>) dfe.getContext();
    // 根据Sensor ID匹配对应的Entity
    SensorEntity sensorEntity = (SensorEntity) contextMap.get("sensorEntity_" + sensor.getId());
    
    SensorType sensorType = SensorType.newBuilder()
            .id(sensorEntity.getSensorTypeId().toString())
            .name(sensorEntity.getSensorTypeName())
            .build();

    return CompletableFuture.completedFuture(sensorType);
}

方式2:自定义上下文类(类型更安全)

定义专属上下文类:

public class SensorQueryContext {
    private Map<UUID, SensorEntity> sensorEntityMap;

    // 构造器、getter、setter方法
}

修改@DgsQuery方法:

@DgsQuery
public List<Sensor> sensors(DgsDataFetchingEnvironment dfe) {
    SensorEntity sensorEntity = sensorRepository.findById(someId);

    SensorQueryContext context = new SensorQueryContext();
    context.setSensorEntityMap(Collections.singletonMap(sensorEntity.getId(), sensorEntity));
    dfe.setContext(context);

    // 剩余Sensor、SensorType初始化代码不变
    // ...

    return Arrays.asList(sensor);
}

数据获取器中读取:

@DgsData(parentType = DgsConstants.SENSOR.TYPE_NAME, field = DgsConstants.SENSOR.SensorType)
public CompletableFuture<SensorType> sensorType(DgsDataFetchingEnvironment dfe) {
    Sensor sensor = dfe.getSource();
    SensorQueryContext context = (SensorQueryContext) dfe.getContext();
    SensorEntity sensorEntity = context.getSensorEntityMap().get(UUID.fromString(sensor.getId()));
    
    // 构建并返回SensorType
    // ...
}

3. 用DataLoader预加载缓存(批量场景推荐)

如果是批量数据场景,推荐使用DGS的DataLoader机制,既可以避免N+1查询,也能复用Query阶段已加载的数据。

首先定义DataLoader:

@DgsDataLoader(name = "sensorTypeLoader")
public class SensorTypeDataLoader extends BatchLoader<UUID, SensorType> {
    private final SensorRepository sensorRepository;

    public SensorTypeDataLoader(SensorRepository sensorRepository) {
        this.sensorRepository = sensorRepository;
    }

    @Override
    public CompletionStage<List<SensorType>> load(List<UUID> sensorTypeIds) {
        // 批量查询数据并转换为SensorType
        List<SensorEntity> entities = sensorRepository.findBySensorTypeIdIn(sensorTypeIds);
        List<SensorType> sensorTypes = entities.stream()
                .map(e -> SensorType.newBuilder()
                        .id(e.getSensorTypeId().toString())
                        .name(e.getSensorTypeName())
                        .build())
                .collect(Collectors.toList());
        return CompletableFuture.completedFuture(sensorTypes);
    }
}

在@DgsQuery中预加载数据到DataLoader缓存:

@DgsQuery
public List<Sensor> sensors(DgsDataFetchingEnvironment dfe) {
    SensorEntity sensorEntity = sensorRepository.findById(someId);

    // 获取DataLoader并将已加载的数据存入缓存
    DataLoader<UUID, SensorType> loader = dfe.getDataLoader("sensorTypeLoader");
    loader.prime(sensorEntity.getSensorTypeId(), 
            SensorType.newBuilder()
                    .id(sensorEntity.getSensorTypeId().toString())
                    .name(sensorEntity.getSensorTypeName())
                    .build());

    // 剩余Sensor、SensorType初始化代码不变
    // ...

    return Arrays.asList(sensor);
}

数据获取器中直接使用DataLoader(自动命中缓存):

@DgsData(parentType = DgsConstants.SENSOR.TYPE_NAME, field = DgsConstants.SENSOR.SensorType)
public CompletableFuture<SensorType> sensorType(DgsDataFetchingEnvironment dfe) {
    Sensor sensor = dfe.getSource();
    UUID sensorTypeId = UUID.fromString(sensor.getSensorType().getId());
    
    // 直接从DataLoader获取,优先使用预加载的缓存数据
    return dfe.getDataLoader("sensorTypeLoader").load(sensorTypeId);
}

内容的提问来源于stack exchange,提问作者Alex Tbk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 00:55:23