如果父对象是单例,创建 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 注入您的单例 UserStateConversationState,然后创建范围并在此范围内解析 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();
        }
    }
}

但是 如果 UserStateConversationState 完成的工作应该作为单个事务执行(这意味着在同一个 DbContext 实例上),最好解析 BotStateSet 中的 MyDbContext 并作为参数传入 UserStateConversationState.

的方法

我不熟悉虚拟助手,但如果可以为您的状态使用 Transient 生命周期 类(至少 UserStateConversationState)它将允许您将 MyDbContext 注入构造函数,避免将其作为参数传递。