ChilliCream / graphql-platform

Welcome to the home of the Hot Chocolate GraphQL server for .NET, the Strawberry Shake GraphQL client for .NET and Banana Cake Pop the awesome Monaco based GraphQL IDE.
https://chillicream.com
MIT License
5.27k stars 748 forks source link

How to map dynamic column in Hot chocolate #6794

Closed Lenny4 closed 11 months ago

Lenny4 commented 11 months ago

Product

Hot Chocolate

Is your feature request related to a problem?

I'm building a GraphQL api with HotChocolate.

Here is my model SimpleModel:

using Microsoft.EntityFrameworkCore;

namespace Model;

public partial class SimpleModel
{
    public string column1 { get; set; } = null!;

    public static void ConfigureModelBuilder(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<SimpleModel>(entity =>
        {
            entity.Property(e => e.column1)
                .HasMaxLength(19)
                .IsUnicode(false)
                .HasColumnName("column1");
        });
    }
}

Here is my table simple_model corresponding to SimpleModel:

column1 column_not_in_model
1 some data
2 other data

As you can see there is an extra column (column_not_in_model) which is not map in the model. I cannot add a property in my SimpleModel corresponding to this column because each user which will use my application should be able to add as many custom column in the database.

Now the question is:

how do I map these customs columns with my model dynamically ?

I want to be able to request the data in column_not_in_model with a graphQl query like so:

query {
  simpleModels(first: 1) {
    totalCount
    edges {
      node {
        column1
        columnNotInModel
      }
    }
  }
}

Here is my Query object:

using Model;
using Microsoft.EntityFrameworkCore;

namespace GraphQl;

public partial class MyDbContext : DbContext
{
    public MyDbContext()
    {
    }

    public MyDbContext(DbContextOptions<MyDbContext> options)
        : base(options)
    {
    }

    public virtual DbSet<SimpleModel> SimpleModels { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        SimpleModel.ConfigureModelBuilder(modelBuilder);
    }

    partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

// https://chillicream.com/docs/hotchocolate/v13/fetching-data/projections
// https://chillicream.com/docs/hotchocolate/v13/fetching-data/projections/#firstordefault--singleordefault
// https://chillicream.com/docs/hotchocolate/v11/fetching-data/pagination#customization
public class Query
{
    // https://chillicream.com/docs/hotchocolate/v12/fetching-data/pagination/#offset-pagination
    [UseOffsetPaging(MaxPageSize = 100, IncludeTotalCount = true, DefaultPageSize = 20)]
    [UseProjection]
    [UseFiltering]
    [UseSorting]
    public IEnumerable<SimpleModel> GetSimpleModels([Service] MyDbContext context) =>
        context.SimpleModels;
}

In my Programs.cs I added the services like this:

// ...
builder.Services
    .AddGraphQLServer()
    .AddQueryType<Query>()
    .AddProjections()
    .AddFiltering()
    .AddSorting();
// ...

I have already look at Dynamic Schemas but it doesn't seems to be what I'm looking for, since Dynamic Schemas allows you to modify the structure of data already mapped in the model.

The solution you'd like

I don't really know what would be the best way to implement this.

cajuncoding commented 11 months ago

By definition, GraphQL is Schema Based with strongly typed data. In essence, your question is how do you manage a dynamically changing Schema? And per the HC docs that is exactly what the Dynamic Schemas feature is for....

Here the docs talk about building your schema during runtime based on types defined in a JSON file... which you would use your SQL DB (or other source) instead of the JSON file used in the example... https://chillicream.com/docs/hotchocolate/v13/defining-a-schema/dynamic-schemas#example-creating-types-from-a-json-file

You will have to take care to safely clear & rebuild your Schema when you change it dynamically.

In addition, you probably will not be able to use Strongly typed models as would normally be used in Hot Chocolate, because your schema will have changes that lose parity with the models (without re-compilation) and/or some other dynamic execution of C# code (which is outside the scope of the question).

Therefore you may also find this Stack Overflow post useful on how to manually and dyanmically process the GraphQL query selections, etc. and use them for dynamic queries.... https://stackoverflow.com/a/68325016/7293142