GraphQL in .NET Core - Part 2

Using Projections - getting related data

In the previous post, we created a simple GraphQL endpoint to server countries to end users using the HotChocoalte framework.

In this post, I am going to show you how we can make use of Projections to allow end users to query related data. In our case, we will allow users to query for countries and ask for cities within those countries.

The pre-requisite is to have the Models already updated to match this relationship. I am assuming that you are familiar with Entity Framework and how to set up 1-to-many relationships.

Here are the two entity models:

public class Country
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<City> Cities { get; set; } = new List<City>();

public class City
    public int Id { get; set; }
    public int CountryId { get; set; }
    public string Name { get; set; }
    public Country Country { get; set; }

As you can see, a country can have multiple cities in it and as such, we are going to use GraphQL to allow users to query for the cities.

The steps involved in enabling this feature in our project are:

  1. Enable Projections in our handler within the Program.cs file:

     using CommanderGQL.Data;  
     using CommanderGQL.GraphQL;  
     using Microsoft.EntityFrameworkCore;  
     var builder = WebApplication.CreateBuilder(args);  
     builder.Services.AddDbContext<AppDbContext>(opt => opt.UseSqlServer("name=CommandConStr"));  
         .AddProjections();  // <-- Add Projections!
     var app = builder.Build();  
     app.UseEndpoints(endpoints => { endpoints.MapGraphQL(); });  
  2. Decorate our query for countries to use projection with the [UseProjection] attribute:

     public IQueryable<Country> GetCountries([Service]AppDbContext context) => context.Countries;

    If you aren't familiar with the code above, check out my previous post on GraphQL as it explains the concept of a query class.

That's all it takes! We can now make a call to our graphQL endpoint:

Notice that the query has been changed - we are asking for cities within countries. The key 'cities' comes from our navigation property within the Countries model.

In the next post, we fix a subtle bug in our code - concurrency.