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

HotChocolate v13中Projection与Data Loader配合失效问题

问题:ASP.NET Core 8 Web API中GraphQL返回Batch但关联Payments始终为null

背景

在ASP.NET Core 8 Web API中使用EF Core,领域模型包含Batch和Payment两个实体,希望通过GraphQL查询返回Batch及其关联的Payment列表,但目前仅Batch数据正常返回,Payments始终为null。

领域实体定义

public class Batch : IEntity
{
    public string InternalId { get; set; }
    public string TenantId { get; set; }
    public string ExternalId { get; set; }
    public List<Payment> Payments { get; set; }
}

public class Payment : IEntity 
{
    public string InternalId { get; set; }
    public string ExternalId { get; set; }
    public decimal Amount { get; set; }
}

GraphQL类型定义

public class Batch 
{
    public string TenantId { get; set; }
    public string ExternalId { get; set; }
    public int? PaymentsCount { get; set; }
    public decimal? TotalAmount { get; set; }
    public List<Payment> Payments { get; set; }

    [DataLoader]
    internal static async Task<ILookup<string, Domain.PaymentBatch.PaymentBatch>> PaymentBatches(IReadOnlyList<string> keys,
        PaymentReadOnlyGraphQLContext paymentReadOnlyGraphQlContext, CancellationToken cancellationToken)
    {
        var batches = await paymentReadOnlyGraphQlContext.PaymentBatches
            .Where(x => keys.Contains(x.TenantId))
            .ToListAsync(cancellationToken);
        return batches.ToLookup(x=>x.TenantId)!;
    }
}

public class Payment 
{
    public string ExternalId { get; set; }
    public decimal Amount { get; set; }
    // 省略其他字段
}

查询定义

public class BatchesQuery
{
    [UsePaging(IncludeTotalCount = true)]
    [UseFiltering]
    [UseSorting]
    public async Task<List<Batch>> Batches(IPaymentBatchesDataLoader paymentBatchDataLoader, string tenantId, [Service] ILogger<BatchesQuery> logger)
    {
        try
        {
            var paymentBatches = await paymentBatchDataLoader.LoadAsync(tenantId, CancellationToken.None);
            return paymentBatches.Select(paymentBatch => new Batch()
                {
                    ExternalId = paymentBatch.ExternalId,
                    PaymentsCount = paymentBatch.Payments?.Count,
                    TotalAmount = paymentBatch.Payments?.SelectMany(x => x.RemittanceDetails).Sum(x => x.Net),
                    Payments = paymentBatch.PaymentRequests.Select(x => new Types.Payment()
                            {
                                ExternalId = x.ExternalId,                              
                                Amount = x.RemittanceDetails.Sum(x => x.Net),
                            })
                            .ToList(),
                    TenantId = paymentBatch.TenantId
                })
                .ToList();
        }
        catch (Exception e)
        {
            logger.LogError(e, "获取批处理数据出错");
            return new List<Batch>();
        }
    }
}

当前问题与疑问

  • 已通过Data Loader从数据库获取Batch数据,但关联的Payments始终为null
  • 不确定是否遗漏配置项,是否需要单独为Payment创建查询和Data Loader
  • 考虑在Batch的Data Loader中添加Include(b=>b.PaymentRequests),但不确定是否正确
  • 已在BatchesQuery上添加[UseProjection]特性,问题仍未解决

解决方案

1. 修复EF Core关联数据加载问题

EF Core默认不会自动加载关联实体(除非开启懒加载,不推荐生产环境使用),必须在查询中通过Include显式指定要加载的关联数据。注意要和领域模型中的属性名保持一致,如果实际关联属性是Payments就用Include(b=>b.Payments),如果是PaymentRequests则对应修改:

[DataLoader]
internal static async Task<ILookup<string, Domain.PaymentBatch.PaymentBatch>> PaymentBatches(IReadOnlyList<string> keys,
    PaymentReadOnlyGraphQLContext paymentReadOnlyGraphQlContext, CancellationToken cancellationToken)
{
    var batches = await paymentReadOnlyGraphQlContext.PaymentBatches
        .Where(x => keys.Contains(x.TenantId))
        .Include(b => b.Payments) // 显式加载关联的Payment数据
        .ToListAsync(cancellationToken);
    return batches.ToLookup(x => x.TenantId)!;
}

2. 修正代码中的语法与映射错误

  • 原GraphQL的Batch类中List<Payment> { get; set; }存在语法错误,需补充属性名Payments
  • 查询中PaymentsCount = paymentBatch.Payments类型不匹配,应改为paymentBatch.Payments?.Count
  • 确认领域模型中的关联属性名和查询中使用的PaymentRequests是否一致,命名不一致会导致赋值失败

3. 确认GraphQL类型配置

确保Payments字段在GraphQL的Batch类型中被正确注册,未被忽略。如果使用Hot Chocolate框架,需确认类型被正确扫描,或通过显式配置声明字段。

4. Data Loader使用说明

当前场景下不需要单独为Payment创建Data Loader,通过Include加载关联数据即可满足需求。后续若有批量查询Payment的场景,再考虑单独实现对应的Data Loader。


内容的提问来源于stack exchange,提问作者vamsi krishna

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 17:57:03