我可以从现有的 DbContext 克隆吗?
Can I clone DbContext from existing one?
我正在开发 .NET Core Web API,我有一个端点,我想在其中并行地 运行 三个操作。他们三个都使用同一个数据库,所以我需要 DbContext 的三个副本。我创建了一个简单的工厂 class,稍后我将其注入我的 "Data" class.
是否可以(如果可以,这是一个好习惯)将 DbContext 注入我的工厂 class(使用内置的 .NET Core IoC),当有人调用 "CreateMyDbContext" 方法时,只需深度克隆一开始注入的那个?
编辑:
以下是 DbContext 池的示例:
public class FooData : IFooData
{
private readonly Func<DisposableScopedContextWrapper> _func;
public FooData(Func<DisposableScopedContextWrapper> func)
{
_func = func;
}
public async Task<List<Apple>> GetApples()
{
using (var wrapper = _func())
{
var apples = await wrapper.Context.Apples.FromSqlRaw("SELECT.... complicated query").ToListAsync();
return apples;
}
}
public async Task<List<Orange>> GetOranges()
{
using (var wrapper = _func())
{
var oranges = await wrapper.Context.Oranges.FromSqlRaw("SELECT.... complicated query").ToListAsync();
return oranges;
}
}
}
public class FooService
{
private readonly IFooData _fooData;
public FooData(IFooData fooData)
{
_fooData = fooData;
}
public async Task<List<Fruit>> GetFruits()
{
var appleTask = _fooData.GetApples();
var orangeTask = _fooData.GetOranges();
(var result1, var result2) = await (appleTask, orangeTask).WhenAll();
// ...
}
}
出于多种原因,我绝对不会推荐任何深度克隆,其中之一是您需要弄清楚很多 EF 内部结构才能使其正确,并且内部结构可能会发生变化(并且您需要花费一些时间在上面)。
第二种选择是手动创建上下文,我不建议这样做也会导致现代基础设施使用 DbContext
池化。
那么您可以像这样注册 Func<DbContext>
(或创建您自己的工厂):
services.AddSingleton<Func<DbContext>>(provider => () =>
{
var scope = provider.CreateScope();
return scope.ServiceProvider.GetRequiredService<DbContext>();
});
这里的问题是这里的作用域不会被释放,你不能(如果你有你的 DbContext
的默认作用域)在 Func
中释放作用域,因为你的上下文将是处置也。所以你可以尝试创建一些一次性包装器,这样你就可以像这样手动处理所有东西:
public class DisposableScopedContextWrapper : IDisposable
{
private readonly IServiceScope _scope;
public DbContext Context { get; }
public DisposableScopedContextWrapper(IServiceScope scope)
{
_scope = scope;
Context = _scope.ServiceProvider.GetService<DbContext>();
}
public void Dispose()
{
_scope.Dispose();
}
}
services.AddSingleton<Func<DisposableScopedContextWrapper>>(provider =>() =>
{
var scope = provider.CreateScope();
return new DisposableScopedContextWrapper(scope);
});
注入你的 类 Func<DisposableScopedContextWrapper> func
并使用它
using (var wrapper = func())
{
wrapper.Context...
}
我正在开发 .NET Core Web API,我有一个端点,我想在其中并行地 运行 三个操作。他们三个都使用同一个数据库,所以我需要 DbContext 的三个副本。我创建了一个简单的工厂 class,稍后我将其注入我的 "Data" class.
是否可以(如果可以,这是一个好习惯)将 DbContext 注入我的工厂 class(使用内置的 .NET Core IoC),当有人调用 "CreateMyDbContext" 方法时,只需深度克隆一开始注入的那个?
编辑: 以下是 DbContext 池的示例:
public class FooData : IFooData
{
private readonly Func<DisposableScopedContextWrapper> _func;
public FooData(Func<DisposableScopedContextWrapper> func)
{
_func = func;
}
public async Task<List<Apple>> GetApples()
{
using (var wrapper = _func())
{
var apples = await wrapper.Context.Apples.FromSqlRaw("SELECT.... complicated query").ToListAsync();
return apples;
}
}
public async Task<List<Orange>> GetOranges()
{
using (var wrapper = _func())
{
var oranges = await wrapper.Context.Oranges.FromSqlRaw("SELECT.... complicated query").ToListAsync();
return oranges;
}
}
}
public class FooService
{
private readonly IFooData _fooData;
public FooData(IFooData fooData)
{
_fooData = fooData;
}
public async Task<List<Fruit>> GetFruits()
{
var appleTask = _fooData.GetApples();
var orangeTask = _fooData.GetOranges();
(var result1, var result2) = await (appleTask, orangeTask).WhenAll();
// ...
}
}
出于多种原因,我绝对不会推荐任何深度克隆,其中之一是您需要弄清楚很多 EF 内部结构才能使其正确,并且内部结构可能会发生变化(并且您需要花费一些时间在上面)。
第二种选择是手动创建上下文,我不建议这样做也会导致现代基础设施使用 DbContext
池化。
那么您可以像这样注册 Func<DbContext>
(或创建您自己的工厂):
services.AddSingleton<Func<DbContext>>(provider => () =>
{
var scope = provider.CreateScope();
return scope.ServiceProvider.GetRequiredService<DbContext>();
});
这里的问题是这里的作用域不会被释放,你不能(如果你有你的 DbContext
的默认作用域)在 Func
中释放作用域,因为你的上下文将是处置也。所以你可以尝试创建一些一次性包装器,这样你就可以像这样手动处理所有东西:
public class DisposableScopedContextWrapper : IDisposable
{
private readonly IServiceScope _scope;
public DbContext Context { get; }
public DisposableScopedContextWrapper(IServiceScope scope)
{
_scope = scope;
Context = _scope.ServiceProvider.GetService<DbContext>();
}
public void Dispose()
{
_scope.Dispose();
}
}
services.AddSingleton<Func<DisposableScopedContextWrapper>>(provider =>() =>
{
var scope = provider.CreateScope();
return new DisposableScopedContextWrapper(scope);
});
注入你的 类 Func<DisposableScopedContextWrapper> func
并使用它
using (var wrapper = func())
{
wrapper.Context...
}