x56*_*657 5 entity-framework entity-framework-core graphql graphql-dotnet dataloader
我正在使用几个数据加载器,它们使用注入的查询服务(反过来又依赖于 DbContext)。它看起来像这样:
Field<ListGraphType<UserType>>(
"Users",
resolve: context =>
{
var loader = accessor.Context.GetOrAddBatchLoader<Guid, IEnumerable<User>>(
"MyUserLoader",
userQueryService.MyUserFunc);
return loader.LoadAsync(context.Source.UserId);
});
Run Code Online (Sandbox Code Playgroud)
Field<ListGraphType<GroupType>>(
"Groups",
resolve: context =>
{
var loader = accessor.Context.GetOrAddBatchLoader<Guid, IEnumerable<Group>>(
"MyGroupLoader",
groupQueryService.MyGroupFunc);
return loader.LoadAsync(context.Source.GroupId);
});
Run Code Online (Sandbox Code Playgroud)
当我运行同时使用两个数据加载器的嵌套查询时,出现异常 "A second operation started on this context before a previous asynchronous operation completed"因为两个数据加载器同时使用相同的 DbContext。
在查询中允许并发数据库访问而不必仔细管理 DbContexts 的最佳方法是什么ServiceLifeTime.Transient?或者数据加载器是否可以公开一种方法来知道何时处理瞬态 DbContext?
从“Scoped”切换到“Transient”并不能解决该问题,因为 Gql.Net 字段解析器是并行执行的。
根据您的示例,我期望您的DbContext构造函数注入到您的“数据库服务”类(userQueryService和groupQueryService)中,并且这些构造函数注入到您的示例 GraphType 类中。因此,您的每个数据库服务都具有完全相同的、有范围的DbContext.
解决方案是延迟解析您的DbContext.
您将更改您的数据库服务以注入IServiceScopeFactory. 然后,您可以在加载器方法(MyUserFunc和MyGroupFunc)中使用它来创建范围,然后解析您的DbContext. 这种方法(“服务定位器”)的问题在于对您的依赖DbContext隐藏在您的类中。
在 CodeReview.StackExchange 上使用这段相对简单的代码来代替使用IServiceScopeFactory<T>. 您无需执行“服务定位器”即可获得延迟解析;您的强类型依赖项在构造函数中声明。
所以假设你的userQueryService变量的类是这样的:
MyDbContext _dbContext;
public UserQueryService(MyDbContext dbContext) => _dbContext = dbContext;
public async Task<IDictionary<Guid, IEnumerable<User>> MyUserFunc(IEnumerable<Guid> userIds)
{
// code that uses _dbContext and returns the data...
}
Run Code Online (Sandbox Code Playgroud)
将其更改为这样(再次使用IServiceScopeFactory<T>):
IServiceScopeFactory<MyDbContext> _dbFactory;
public UserQueryService(IServiceScopeFactory<MyDbContext> dbFactory) => _dbFactory = dbFactory;
public async Task<IDictionary<Guid, IEnumerable<User>> MyUserFunc(IEnumerable<Guid> userIds)
{
using var scope = _dbFactory.CreateScope();
var dbContext = scope.GetRequiredService();
// code that uses dbContext and returns the data...
}
Run Code Online (Sandbox Code Playgroud)
现在,当 Gql.Net 的解析器(在本例中是数据加载器)最终执行此方法时,您的每次使用都使用DbContext自己的作用域,因此它们不会像您现在那样出现执行问题。
| 归档时间: |
|
| 查看次数: |
783 次 |
| 最近记录: |