JacekKosciesza / StarWars

GraphQL 'Star Wars' example using GraphQL for .NET, ASP.NET Core, Entity Framework Core
MIT License
623 stars 98 forks source link

How get CharacterFriends from DroidType? #1

Closed janskoruba closed 7 years ago

janskoruba commented 7 years ago

Hello,

How can I get CharacterFriends in DroidType?

    {
        public DroidType()
        {
            Field(x => x.Id).Description("The Id of the Droid.");
            Field(x => x.Name, nullable: true).Description("The name of the Droid.");
            Field(x => x.PrimaryFunction, true).Description("Primary function of the Droid.");

            //I have tried something like this:
            //but it is possible probably only for properties not for collections
            Field(x => x.CharacterFriends).Description("List of friends.");

        }
    }

Thank you. Jan

JacekKosciesza commented 7 years ago

I'm working on this. I will probably commit example code this weekend.

janskoruba commented 7 years ago

OK, thank you.

janskoruba commented 7 years ago

Is it possible create a sample with generate SQL query according GraphQL query?

I've wondered about scenario where I have a query like this:

{
user: {
 id,
 name,
 friends: [
 id,
 name
 ]
}
}
SELECT id, name ... FROM dbo.[User]
INNER JOIN dbo.[UserFriends ] ....

and simple version only list of users with id a name (without friends):

{
user: {
 id,
 name
}
}

SELECT id, name FROM dbo.[User]

Is it possible create map GraphQL to specific SQL command like above? Thanks

JacekKosciesza commented 7 years ago

@janskoruba Check dev branch for my today's experiments with more advanced queries (including droid friends). Generally it works, but I'm struggling with some stack overflow exceptions, related to circular reference (data from Entity Framework). I have to figure out what I'm doing wrong and fix it.

JacekKosciesza commented 7 years ago

more-advanced-queries

janskoruba commented 7 years ago

@JacekKosciesza Thank you so much for your great sample. Is it possible affected the result sql query according the qraphql query? Because if you have call the hero query above but without friends the result sql is with friends still. What do you think about that? :)

JacekKosciesza commented 7 years ago

Circular references problem is fixed - I've changed AutoMapper configuration. I've also fixed some of the integration tests. Right now only one scenario is not supported - I will take care of it next. integration-tests-one-missing-scenario

JacekKosciesza commented 7 years ago

As far as your SQL queries questions are concerned - I will look at this next (when I finish advanced queries). Please open separate issue for this (let's keep things in order). I will close this issue when merged to master.

janskoruba commented 7 years ago

OK, thank you. I will open new issue.

janskoruba commented 7 years ago

The guys from GraphQL.NET library recommended for getting collection another way to do that I've tried following - It could be interesting for you as well:

For getting Episodes - For testing only ids - CharacterId, EpisodeId

public class DroidType : ObjectGraphType<Droid>
    {
        public DroidType()
        {
            Field(x => x.Id).Description("The Id of the Droid.");
            Field(x => x.Name, nullable: true).Description("The name of the Droid.");

           //This another way
            Field(name: "Episodes", description: "The friends of the user",
                type: typeof(ListGraphType<CharacterEpisodeType>),
                resolve: context => context.Source.CharacterEpisodes);
        }
    }

    public class CharacterEpisodeType : ObjectGraphType<CharacterEpisode>
    {
        public CharacterEpisodeType()
        {
            Field(x => x.CharacterId);
            Field(x => x.EpisodeId);
        }
    }

This is query to getting the Droid with Episodes:

public async Task<IEnumerable<Droid>> GetDroidEpisodes()
        {
            var droids = await _db.Set<Droid>().Include(x => x.CharacterEpisodes).ToListAsync();

            return droids;
        }

And add GraphQL Query:

Field<ListGraphType<DroidType>>(
                "heroes",
                resolve: context => _droidRepository.GetDroidEpisodes()
            );
JacekKosciesza commented 7 years ago

Both approaches have some pros and cons. With above implementation you are always fetching episodes (whether it is needed or not), so you are doing extra SQL join. With my current implementation, when it is not needed I don't fetch it, but when it is needed there is an extra SQL query. Probably there is some way of checking if episodes are requested by GraphQL query and perform fetching droid with or without episodes - that would be the best approach. I don't think that it will work for friends, and queries like 'give me friends of friends of friends of hero' - in this case I think it is easier to do extra queries.

janskoruba commented 7 years ago

Yes, you are right, this don't solve problem with create IQueryable according the QraphQL query.