GraphQL查询与表加入
问题描述:
我正在学习GraphQL
所以我建立了一个小项目。假设我有2个型号,User
和Comment
。GraphQL查询与表加入
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:很多,用户可以有很多评论。
我已经建立了这样的模式:
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个查询,一个用于用户,另一个用于他的评论。
我的问题是,构建GraphQL
模式和类型以及在表之间组合联接的最佳实践是什么,以便服务器也可以使用1请求执行查询?
答
您引用的概念称为批处理。有几个图书馆提供这个功能。例如:
Dataloader:被Facebook保持通用应用程序,提供 “在各种后端一致的API并通过配料和缓存减少请求那些后端”
-
join-monster
:“A GraphQL-TO-用于批量数据提取的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;
}
}
}
}
假设我们有以下查询:
var include = context.GetIncludeString();
产生以下字符串:
query {
getHistory {
id
product {
id
category {
id
subCategory {
id
}
subAnything {
id
}
}
}
}
}
我们可以在现场的 “决心” 的方法创建一个变量
"Product.Category.SubCategory,Product.Category.SubAnything"
和它传递到实体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));
}
如果你喜欢的视频,在这里是一个谈加入怪物:https://www.youtube.com/watch?v=Y7AdMIuXOgs :) – marktani
谢谢您为您的文章。你会选哪一个?一方面,我有脸书和1800星级图书馆批量一些请求,但另一方面,我有一个图书馆批量一切到1请求。 – itaied
我们在Graphcool的Dataloader上做了很好的体验,当时我们使用graphql-js运行一个节点GraphQL后端。无法分享加入怪物的任何经验。我认为它们在功能和用法上略有差异,所以你需要测试它我猜:) – marktani