ita*_*ied 26 sql node.js sequelize.js graphql
我正在学习,GraphQL所以我建了一个小项目.假设我有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,
});
Run Code Online (Sandbox Code Playgroud)
关系是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()
}
})
});
Run Code Online (Sandbox Code Playgroud)
和查询:
const user = {
type: UserType,
args: {
id: {
type: new GraphQLNonNull(GraphQLString)
}
},
resolve(_, {id}) => User.findById(id)
};
Run Code Online (Sandbox Code Playgroud)
执行用户的查询和他的评论是通过1个请求完成的,如下所示:
{
User(id:"1"){
Comments{
content
}
}
}
Run Code Online (Sandbox Code Playgroud)
据我了解,客户端将使用1个查询获得结果,这是使用的好处GraphQL.但是服务器将执行2个查询,一个用于用户,另一个用于他的注释.
我的问题是,构建GraphQL模式和类型以及组合表之间的连接的最佳实践是什么,以便服务器也可以使用1个请求执行查询?
mar*_*ani 13
您所指的概念称为批处理.有几个图书馆提供这个.例如:
Dataloader:由Facebook维护的通用实用程序,提供"在各种后端上提供一致的API,并通过批处理和缓存减少对这些后端的请求"
join-monster:"用于批量数据提取的GraphQL-to-SQL查询执行层."
对于使用.NET和GraphQL for .NET软件包的任何人,我都做了一个扩展方法,可以将GraphQL查询转换为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;
}
}}}
Run Code Online (Sandbox Code Playgroud)
可以说我们有以下查询:
query {
getHistory {
id
product {
id
category {
id
subCategory {
id
}
subAnything {
id
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
我们可以在字段的“解决”方法中创建一个变量:
var include = context.GetIncludeString();
Run Code Online (Sandbox Code Playgroud)
生成以下字符串:
"Product.Category.SubCategory,Product.Category.SubAnything"
Run Code Online (Sandbox Code Playgroud)
并将其传递给实体框架:
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));
}
Run Code Online (Sandbox Code Playgroud)