简体   繁体   中英

Nested queries with graphql in c#

Im trying to implement a graphql api in c#. I have the basics working but i am struggling to get the nested queries working.

I have seen it implemented in the likes of NodeJS and others. I was just wondering if someone could help me implement the same in c#.

basic types:

 public AirportType()
    {
        Name = "Airport";

        Field(x => x.Id, type: typeof(IdGraphType)).Description("The ID of the Airport.");
        Field(x => x.Name).Description("The name of the Airport");
        Field(x => x.Location).Description("The Location of the Airport");
        Field(x => x.Plane,nullable:true, type: typeof(ListGraphType<PlaneType>)).Description("Aiports Planes");

    }


  public PlaneType()
    {
        Name = "Plane";

        Field(x => x.Id, type: typeof(IdGraphType)).Description("The ID of the Plane.");
        Field(x => x.Model).Description("The model of the Plane");
        Field(x => x.Callsign).Description("The callsign of the Plane");
        Field(x => x.AirportId,nullable:true).Description("The parent Aiport");
        Field(x => x.Pilot,nullable:true, type: typeof(ListGraphType<PilotType>)).Description("The Planes Pilots");
    }



 public PilotType()
    {
        Name = "Pilot";

        Field(x => x.Id, type: typeof(IdGraphType)).Description("The ID of the Pilot.");
        Field(x => x.Name).Description("The name of the Pilot");
        Field(x => x.Surname).Description("The surname of the Pilot");
        Field(x => x.PlaneId,nullable: true).Description("The parent Plane");
    }

and the basic queries:

 Field<AirportType>(
            "airport",
            arguments: new QueryArguments(
                new QueryArgument<IdGraphType> { Name = "id", Description = "The ID of the aiport." }),
            resolve: context =>
            {
                var id = context.GetArgument<int?>("id");
                var airport = db.Airport.Include("Plane.Pilot").FirstOrDefault(i => i.Id == id);

                return airport;
            });
        Field<ListGraphType<AirportType>>(
            "airports",
            resolve: context =>
            {
                var airports = db.Airport.Include("Plane.Pilot");

                return airports;
            });
        Field<ListGraphType<PlaneType>>(
            "planes",
            resolve: context =>
            {
                var planes = db.Plane.Include("Pilot").Include("Airport");

                return planes;
            });

AirportType, PilotType and PlaneType need to extend ObjectGraphType<>

public class Airport
{
    public IdGraphType Id { get; set; }
    public string Name { get; set; }
    public string Location { get; set; }
    public PlaneType Plane { get; set; }
}

public class AirportType : ObjectGraphType<Airport>
{
    public AirportType()
    {
        Name = "Airport";

        Field(x => x.Id, type: typeof(IdGraphType)).Description("The ID of the Airport.");
        Field(x => x.Name).Description("The name of the Airport");
        Field(x => x.Location).Description("The Location of the Airport");
        Field(x => x.Plane, nullable: true, type: typeof(ListGraphType<PlaneType>)).Description("Aiports Planes");
    }
}

public class Pilot
{
    public IdGraphType Id { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public IdGraphType PlaneId { get; set; }
}

public class PilotType : ObjectGraphType<Pilot>
{
    public PilotType()
    {
        Name = "Pilot";

        Field(x => x.Id, type: typeof(IdGraphType)).Description("The ID of the Pilot.");
        Field(x => x.Name).Description("The name of the Pilot");
        Field(x => x.Surname).Description("The surname of the Pilot");
        Field(x => x.PlaneId, nullable: true).Description("The parent Plane");
    }
}

public class Plane
{
    public IdGraphType Id { get; set; }
    public string Model { get; set; }
    public string Callsign { get; set; }
    public string AirportId { get; set; }
    public PilotType Pilot { get; set; }
}

public class PlaneType : ObjectGraphType<Plane>
{
    public PlaneType()
    {
        Name = "Plane";

        Field(x => x.Id, type: typeof(IdGraphType)).Description("The ID of the Plane.");
        Field(x => x.Model).Description("The model of the Plane");
        Field(x => x.Callsign).Description("The callsign of the Plane");
        Field(x => x.AirportId, nullable: true).Description("The parent Aiport");
        Field(x => x.Pilot, nullable: true, type: typeof(ListGraphType<PilotType>)).Description("The Planes Pilots");
    }
}

The GraphQL Query class must also extend ObjectGraphType

public class MyQuery : ObjectGraphType
{
    public MyQuery(IAirForceRepository db)
    {
        Field<AirportType>(
            "airport",
            arguments: new QueryArguments(
                new QueryArgument<IdGraphType> { Name = "id", Description = "The ID of the airport." }),
            resolve: context =>
            {
                var id = context.GetArgument<int?>("id");
                var airport = db.Airport.Include("Plane.Pilot").FirstOrDefault(i => i.Id == id);

                return airport;
            });
        Field<ListGraphType<AirportType>>(
            "airports",
            resolve: context =>
            {
                var airports = db.Airport.Include("Plane.Pilot");

                return airports;
            });
        Field<ListGraphType<PlaneType>>(
            "planes",
            resolve: context =>
            {
                var planes = db.Plane.Include("Pilot").Include("Airport");

                return planes;
            });
    }
}

In order to query sub entities (for example Plane and then Pilot), you need to add a Connection between the two. In this example, between Plane and Pilot, where Plane is the root and Pilot is the sub entity, the two classes must to be modified like below

Modified Plane class

public class Plane
{
    public IdGraphType Id { get; set; }
    public string Model { get; set; }
    public string Callsign { get; set; }
    public string AirportId { get; set; }
    public PilotType Pilot { get; set; }
    public Connection<Pilot> PilotConnection { get; set; }

    public Plane()
    {
        PilotConnection = new Connection<Pilot>
        {
            TotalCount = 3,

            PageInfo = new PageInfo
            {
                HasNextPage = false,
                HasPreviousPage = false,
                StartCursor = "0",
                EndCursor = "2",
            },

            Edges = new List<Edge<Pilot>>
            {
                new Edge<Pilot> {Cursor = "0", Node = new Pilot { Name = "Johnny", Id = new IdGraphType() }},
                new Edge<Pilot> {Cursor = "1", Node = new Pilot { Name = "Ronny", Id = new IdGraphType() }},
                new Edge<Pilot> {Cursor = "2", Node = new Pilot {Name = "Jimmy", Id = new IdGraphType() }}
            }
        };
    }
}

Modified PlaneType class

public class PlaneType : ObjectGraphType<Plane>
    {
        public PlaneType()
        {
            Name = "Plane";

            Field(x => x.Id, type: typeof(IdGraphType)).Description("The ID of the Plane.");
            Field(x => x.Model).Description("The model of the Plane");
            Field(x => x.Callsign).Description("The callsign of the Plane");
            Field(x => x.AirportId, nullable: true).Description("The parent Aiport");
            Field(x => x.Pilot, nullable: true, type: typeof(ListGraphType<PilotType>)).Description("The Planes Pilots");
            Connection<PilotType>()
                .Name("pilots")
                .Description("Pilots that drive this plane")
                .Resolve(context => context.Source.PilotConnection);
        }
    }

Then you can perform a query to the connection to that sub entity, but without giving it an argument (for example id:"1"), like in the example below

query {
    plane(id: "1"){
        id
        model
        callsign
        airportid
        pilot {
            edges {
                node {
                id
                name
                }
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM