问题描述
我在实体框架中使用 HotChocolate。对于某些字段,我们希望过滤一对多集合。 示例:
public class Many
{
public int Id { get; set; }
public string? Name {get; set; }
}
public class User
{
public int Id { get; set; }
public List<Many> Manies { get; set; }
}
public class UserType : ObjectType<User>
{
protected override void Configure(IObjectTypeDescriptor<User> descriptor)
{
descriptor.BindFieldsExplicitly();
descriptor.Field(u => u.Id);
descriptor.Field("manies").Resolve(c => c.Parent<User>().Manies.Where(m => m.Name.StartsWith("A")).ToList());
}
}
我的第一个问题是:解析器是否按照 Concat for v10 所述并行执行?
我在解析器中使用 async/await 时也遇到了问题。似乎在那种情况下(并且仅在这种情况下)解析器是在另一个线程上启动的(而且我遇到了 DbContext 并行执行的问题)。
示例:
descriptor.Field("manies").Resolve(async c => {
var parent = c.Parent<User>();
return await GetFilterManiesAsync(parent);
});
但是当我强制同步时,没有并行问题:
descriptor.Field("manies").Resolve(c => {
var parent = c.Parent<User>();
return GetFilterManiesAsync(parent).Result;
});
所以我想了解一下,这是 HotChocolate 中的错误吗?或者并行管道仅在 async/await 解析器上启动。
附言使用 HotChocolate v11.0.9
谢谢,
解决方法
我建议您阅读他们的官方graphql-workshop,其中讨论了这个问题以及其他很多内容。其中的一个讲座包含以下段落:
GraphQL 执行引擎将始终尝试执行 并行以优化数据获取并减少等待时间。 实体框架将有一个问题,因为 DBContext 是 不是线程安全的。
解决这个问题的方法是使用 lexer.mll
池化。使用 DbContext
池化允许您为每个需要一个的字段发出一个 DBContext
实例。但不是为每个字段创建一个 DBContext
实例并在使用后将其丢弃,而是租用以便字段和请求可以重用它。
要进行设置,您必须将 DBContext
的注册从 DbContext
更改为 services.AddDbContext<YourContext>(options => ...);
。然后,您需要将 services.AddPooledDbContextFactory<YourContext>(options => ...);
注册为范围服务,每次从代码的某些部分访问时,该服务都会从工厂本身解析。这样您就可以让库本身做它的事情并并行解析字段。
我不确定当您调用 YourContext
并强制执行同步时会发生什么,但我猜您通过这样做以某种方式设法阻止了整个并行场解析。