如果父对象是单例,创建 dbcontext(EF 核心)的最佳做法是什么?
What is the best practice for creating dbcontext (EF core) if the parent object is a singleton?
我用Virtual Assistant。我将使用 Entity Framework Core 来保存状态。我遇到了一个问题。 IStorage 接口像单例一样注入,因为使用此接口的其他对象作为单例注入。
services.AddSingleton<IStorage>(new MyDbStorage()); //<-- my storage with dbcontext
services.AddSingleton<UserState>(); //This class has ctor with IStorage param
services.AddSingleton<ConversationState>(); //And this class has ctor with IStorage param
services.AddSingleton(sp =>
{
var userState = sp.GetService<UserState>();
var conversationState = sp.GetService<ConversationState>();
return new BotStateSet(userState, conversationState);
});
有关详细信息,请参阅 github。
我知道,the global dbcontext is a bad idea。
你能建议我一些创建 dbcontext 的选项吗?
我想到了 DbContextFactory,但我不知道具体如何创建它。
更新
我已经更新了代码。见第一行。
首先不要用interface抽象MyDbContext
,否则你将无法访问EF的features或试图隐藏EntityFramework
命名空间。使用 AddDbContext 扩展名。这样 DbContext
将被注册为 Scoped
什么是它的最佳生命周期。
将 IServiceProvider
注入您的单例 UserState
和 ConversationState
,然后创建范围并在此范围内解析 MyDbContext
实例 仅按需。
public class UserState
{
private readonly IServiceProvider _provider;
public UserState(IServiceProvider provider)
{
_provider = provider;
}
public async Task DoWorkAsync()
{
using (var scope = _provider.CreateScope())
using (var ctx = scope.ServiceProvider.GetService<MyDbContext>())
{
// do work
await ctx.SaveChangesAsync();
}
}
}
但是 如果 UserState
和 ConversationState
完成的工作应该作为单个事务执行(这意味着在同一个 DbContext
实例上),最好解析 BotStateSet
中的 MyDbContext
并作为参数传入 UserState
和 ConversationState
.
的方法
我不熟悉虚拟助手,但如果可以为您的状态使用 Transient
生命周期 类(至少 UserState
和 ConversationState
)它将允许您将 MyDbContext
注入构造函数,避免将其作为参数传递。
我用Virtual Assistant。我将使用 Entity Framework Core 来保存状态。我遇到了一个问题。 IStorage 接口像单例一样注入,因为使用此接口的其他对象作为单例注入。
services.AddSingleton<IStorage>(new MyDbStorage()); //<-- my storage with dbcontext
services.AddSingleton<UserState>(); //This class has ctor with IStorage param
services.AddSingleton<ConversationState>(); //And this class has ctor with IStorage param
services.AddSingleton(sp =>
{
var userState = sp.GetService<UserState>();
var conversationState = sp.GetService<ConversationState>();
return new BotStateSet(userState, conversationState);
});
有关详细信息,请参阅 github。 我知道,the global dbcontext is a bad idea。 你能建议我一些创建 dbcontext 的选项吗? 我想到了 DbContextFactory,但我不知道具体如何创建它。
更新 我已经更新了代码。见第一行。
首先不要用interface抽象MyDbContext
,否则你将无法访问EF的features或试图隐藏EntityFramework
命名空间。使用 AddDbContext 扩展名。这样 DbContext
将被注册为 Scoped
什么是它的最佳生命周期。
将 IServiceProvider
注入您的单例 UserState
和 ConversationState
,然后创建范围并在此范围内解析 MyDbContext
实例 仅按需。
public class UserState
{
private readonly IServiceProvider _provider;
public UserState(IServiceProvider provider)
{
_provider = provider;
}
public async Task DoWorkAsync()
{
using (var scope = _provider.CreateScope())
using (var ctx = scope.ServiceProvider.GetService<MyDbContext>())
{
// do work
await ctx.SaveChangesAsync();
}
}
}
但是 如果 UserState
和 ConversationState
完成的工作应该作为单个事务执行(这意味着在同一个 DbContext
实例上),最好解析 BotStateSet
中的 MyDbContext
并作为参数传入 UserState
和 ConversationState
.
我不熟悉虚拟助手,但如果可以为您的状态使用 Transient
生命周期 类(至少 UserState
和 ConversationState
)它将允许您将 MyDbContext
注入构造函数,避免将其作为参数传递。