GraphQL查询与表连接
我正在学习GraphQL
所以我build立了一个小项目。 比方说,我有2个模型, User
和Comment
。
const Comment = Model.define('Comment', { content: { type: DataType.TEXT, allowNull: false, validate: { notEmpty: true, }, }, }); const User = Model.define('User', { name: { type: DataType.STRING, allowNull: false, validate: { notEmpty: true, }, }, phone: DataType.STRING, picture: DataType.STRING, });
关系是1:很多,用户可以有很多评论。
我已经build立了这样的架构:
const UserType = new GraphQLObjectType({ name: 'User', fields: () => ({ id: { type: GraphQLString }, name: { type: GraphQLString }, phone: { type: GraphQLString }, comments: { type: new GraphQLList(CommentType), resolve: user => user.getComments() } }) });
和查询:
const user = { type: UserType, args: { id: { type: new GraphQLNonNull(GraphQLString) } }, resolve(_, {id}) => User.findById(id) };
执行一个用户的查询和他的意见是由1请求完成,如下所示:
{ User(id:"1"){ Comments{ content } } }
据我所知,客户将得到使用1查询的结果,这是使用GraphQL
的好处。 但服务器将执行2个查询,一个用于用户,另一个用于他的评论。
我的问题是,什么是build立GraphQL
模式和types和组合表之间的GraphQL
的最佳做法,以便服务器也可以执行查询1请求?
您所指的概念称为批处理。 有几个图书馆提供这个。 例如:
-
Dataloader :由Facebook维护的通用实用程序,提供“通过各种后端一致的API,并通过批处理和caching减less对后端的请求”
-
join-monster :“批量数据抓取的GraphQL到SQL查询执行层”
对于任何使用.NET和GraphQL for .NET软件包的人来说,我已经制作了一个将GraphQL Query转换为Entity Framework Includes的扩展方法。
public static class ResolveFieldContextExtensions { public static string GetIncludeString(this ResolveFieldContext<object> source) { return string.Join(',', GetIncludePaths(source.FieldAst)); } private static IEnumerable<Field> GetChildren(IHaveSelectionSet root) { return root.SelectionSet.Selections.Cast<Field>().Where(x => x.SelectionSet.Selections.Any()); } private static IEnumerable<string> GetIncludePaths(IHaveSelectionSet root) { var q = new Queue<Tuple<string, Field>>(); foreach (var child in GetChildren(root)) { q.Enqueue(new Tuple<string, Field>(child.Name.ToPascalCase(), child)); } while (q.Any()) { var node = q.Dequeue(); var children = GetChildren(node.Item2).ToList(); if (children.Any()) { foreach (var child in children) { q.Enqueue(new Tuple<string, Field>(node.Item1 + "." + child.Name.ToPascalCase(), child)); } } else { yield return node.Item1; } } } }
可以说我们有以下查询:
query { getHistory { id product { id category { id subCategory { id } subAnything { id } } } } }
我们可以在字段的“parsing”方法中创build一个variables:
var include = context.GetIncludeString();
它会生成以下string:
"Product.Category.SubCategory,Product.Category.SubAnything"
并传递给Entity Framwork:
public Task<TEntity> Get(TKey id, string include) { var query = Context.Set<TEntity>(); if (!string.IsNullOrEmpty(include)) { query = include.Split(',', StringSplitOptions.RemoveEmptyEntries).Aggregate(query, (q, p) => q.Include(p)); } return query.SingleOrDefaultAsync(c => c.Id.Equals(id)); }