EF 的 DbContext 的单例范围

Singleton Scope for EF's DbContext

所以我目前正在开发一个使用 Entity Framework 的 ASP.NET MVC 网络应用程序,我也在使用 Ninject 进行依赖注入。

目前,基本上,这就是我使用 Ninject.

注册我的 DbContext 和服务的方式
kernel.Bind<DbContext>().To<MyApplicationContext>().InSingletonScope();
kernel.Bind<IAccountService>().To<AccountService>().InSingletonScope();
kernel.Bind<IRegionService>().To<RegionService>().InSingletonScope();
kernel.Bind<IRoleService>().To<RoleService>().InSingletonScope();

我用 InSingletonScope 注册它们,这意味着它们只会创建一次并在应用程序的整个生命周期中使用(至少我是这样理解的)。

控制器:

private IAccountService _accountService;

public MemberController(IAccountService accountService)
{
    _accountService = accountService;
}

但是,我有一种深刻的感觉,这个单例范围会在我的 Web 应用程序中引起问题,特别是对于 Entity Framework 的上下文,因为它是单例。

因此,我已经面临一个小问题,如果我使用 SQL Management Studio 手动更新数据库,我的 Web 应用程序 Entity Framework 中的数据将不会更新,直到我重新启动应用程序(似乎是 EF 中的某种缓存机制)。

--

但是,如果我删除 InSingletonScope,我会随机收到 EF 的错误消息:

An entity object cannot be referenced by multiple instances of IEntityChangeTracker

我理解为什么会发生这种情况,因为 AccountService 初始化的 DbContext 可能不同于 RegionService。但是我不知道如何解决这个问题。

我对Dependency Injection的理解还很有限,请大家指点一下?

--

编辑: 我已经尝试将所有注射更改为 InRequestScope,但我仍然得到

An entity object cannot be referenced by multiple instances of IEntityChangeTracker

尝试从我的应用程序中的其他服务插入具有相关对象(外键)的新实体时。这意味着他们仍在使用不同的 DbContext,这是怎么回事?!

最终编辑: 好的,我发现了问题,是我的缓存机制缓存了先前的请求,导致所有后续请求出现关系问题。

单例范围对于您的上下文来说是一个非常糟糕的主意。请求范围是您应该使用的,因为它本质上是请求生命周期的单例。

至于为什么您在使用请求范围时出错,我不能肯定地说。假设您正在使用的实体都来自相同的上下文类型,并且您在需要的任何地方都正确地注入了上下文,那么永远不应该有多个上下文实例在起作用。

编辑

重新阅读您的问题后,听起来好像您的服务实际上正在初始化其构造函数或其他内容中的上下文。如果是这样,那是你的问题。您的上下文应该注入到您的服务中,即:

public class AccountService : IAccountService
{
    protected readonly DbContext context;

    public AccountService(DbContext context)
    {
        this.context = context;
    }

    ...
}

然后,Ninject 将在更新任何服务时正确注入 MyApplicationContext 的请求范围实例。

Dan,当您为整个应用程序限定单个 DBContext 时,您正在制造瓶颈。在引擎盖下,Entity Framework 将相当有效地处理您需要的对象数量。如果您深入了解内部结构,接触数据库的实际对象会做同样的事情。因此,您尝试通过制作单例进行优化实际上可能会产生一个非常大的问题。

我终于通过使用 InRequestScope 而不是 InSingletonScope 解决了这个问题。

最初,由于我的服务层上存在缓存机制,因此在更改为 InRequestScope 后我仍然面临同样的问题。

因此,所有后续请求都使用初始缓存的实体对象,这就是我从 EF 收到多个实例错误的原因。

--

如果你还面临

An entity object cannot be referenced by multiple instances of IEntityChangeTracker

更改为 InRequestScope 后出错,请确保您的实体未以某种方式缓存或存储以供后续 HTTP 请求使用。

包括DbContext在内的一些服务的lifetime可以这样配置:

services.AddDbContext<ApplicationDbContext>(
    options => { options.UseSqlServer("YourConnectionString"); },
    ServiceLifetime.Singleton);

REF