12

I am working on converting a shodily designed REST API into a smooth GraphQL API with Entity Framework Core and Hot Chocolate.

I am currently exposing my entire database via UseProjection. My database contains a table Foo with a foreign key to table Bar which has property Baz.

This is currently exposed as:

Foo {
  Bar {
    Baz
  }
}

In my case, Foo and Bar have a 1:1 relationship. I would like to hide Bar from the API, and expose the following:

Foo {
  Baz
}

I have added the following in FooType.cs:

descriptor
    .Field("Baz")
    .Resolve(ctx => ctx.Parent<Foo>().Bar?.Baz);

If I run a query that accesses Baz at both levels then GQL correctly returns Baz at both levels. However, if I omit the 3-level request, then the SQL call never pulls Baz from the database, and therefore the 2-level request returns null.

The Hot Chocolate docs say you can fix this problem by adding:

descriptor
    .Field(Foo => Foo.Bar)
    .IsProjected(true);

However, when I run a query with this code in place, I receive an error A composite type always needs to specify a selection set. So I not only need to tell Hot Chocolate to project Bar, but also specify a set of fields in Bar? How do I do that?

P.S. I can get around the above error by explicitly adding fields to the query, but I don't want to pollute my query.

P.P.S I can also do it by resolving Foo.Bar with a DataLoader, but since I have ~1k Foos each with a unique Bar and unique Baz, that would require ~1k database calls. I want to do this in one call.

Hot Chocolate v11, netcore3.1

EDIT

IsProjected(true) is meant to be used on a property, not a table. The question becomes, how do I project across a table into a property?

Braden Cok
  • 151
  • 1
  • 7

1 Answers1

0

Perhaps you need to tell EF to "auto include" your navigation property Baz: https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.metadata.builders.navigationbuilder.autoinclude?view=efcore-6.0

Ex:

public class BarConfig : IEntityTypeConfiguration<Bar>
{
    public void Configure(EntityTypeBuilder<Bar> builder)
    {
        builder.Navigation(x => x.Baz).AutoInclude();
    }
}