Home > Enterprise >  GraphQL query is null
GraphQL query is null

Time:04-20

I'm using graphQL hot chocolate and need to fetch data. I need to fetch data from Template that has Specs and in spec it contains AttributeType. when i try to query the data, template and spec has values but AttributeType is null that should not be. here are my entities:

Template

public         long            Id          { get; set; }
public         bool            IsDeleted   { get; set; }
public         string          Name        { get; set; }
public         long            SpecId      { get; set; }
public virtual List<Spec>      Specs       { get; set; }

Spec

public long           Id              { get; set; }
public int            Position        { get; set; }
public string         Label           { get; set; }
public bool           IsDeleted       { get; set; }

public virtual AttributeType  AttributeType   { get; set; }
public         long           AttributeTypeId { get; set; }

public Template Template    { get; set; }
public long?    TemplateId  { get; set; }

and finally AttributeType

public         long            Id          { get; set; }
public         string          Description { get; set; }
public         string          Format      { get; set; }

I used Dataloader and resolver to fetch the data

[Authorize]
[GraphQLType( typeof(TemplateObjectType) )]
public  Task<Template> GetTemplateById( long id, TemplateDataLoader dataLoader, CancellationToken cancellationToken )
  => dataLoader.LoadAsync( id, cancellationToken );
public class TemplateObjectType: ObjectType<Template>
{
    protected override void Configure( IObjectTypeDescriptor<Template> descriptor )
    {
      descriptor.Field( x => x.Specs)
                .ResolveWith<TemplateResolver>( r => r.GetSpecsAsync( default, default, default ) );
    }
}

public async Task<IReadOnlyList<Spec>> GetSpecAsync(
    [Parent] Template template,
    SpecDataLoader dataLoader,
    CancellationToken   cancellationToken)
        => await dataLoader.LoadAsync(template.Id, cancellationToken);
    
protected override async Task<ILookup<long, Spec>> LoadGroupedBatchAsync( IReadOnlyList<long> keys, CancellationToken cancellationToken )
{
    var result = await _dbContext.Templates
                                 .Where( template => keys.Contains( template.Id ) )
                                 .Select( x => new {
                                                       TemplateId= x.Id,
                                                       x.Specs
                                                   } )
                                 .ToListAsync( cancellationToken: cancellationToken );

    var final = result
                .Select(x => x.Specs.Select(c => new
                                                      {
                                                        x.TemplateId,
                                                        Spec= c
                                                      }))
                .SelectMany(x => x)
                .ToLookup(x => x.TemplateId, x => x.Spec);

    return final;
}

When I query GetTemplateById I get the result but AttributeType is null which shouldn't be, here is a sample of the query:

"data": {
    "templatebyId": {
        "name": "test",
        "specs": [
            {
                "id": 4,
                "position": 0,
                "label": "price",
                "templateId": 1,
                "attributeType": null
            }
        ]
    }
}

CodePudding user response:

By default EF tries to optimize the amount of data fetched from the database. As your code is now, the attributes are not loaded.

You should either include the attributes in this call, or omit the ToListAsync to have EF determine you'll need the data in a later stage.

var result = await _dbContext.Templates
                               .Where( template => keys.Contains( template.Id ) )
                               .Select( x => new {
                                                   TemplateId= x.Id,
                                                   x.Specs
                                                 } )
                               .ToListAsync( cancellationToken: cancellationToken );

Using Include/ThenInclude will tell the framework to include the data:

var result = await _dbContext.Templates
                           .Where( template => keys.Contains( template.Id ) )
                           .Include(prop => prop.Specs)
                           .ThenInclude(spec => spec.AttributeType) 
                           .Select( x => new {
                                               TemplateId= x.Id,
                                               x.Specs
                                             } )
                           .ToListAsync( cancellationToken: cancellationToken );
  • Related