EF的DbContext的单例范围

时间:2015-03-19 19:53:35

标签: c# asp.net-mvc entity-framework dependency-injection ninject

所以我目前正在使用一个使用Entity Framework的ASP.NET MVC Web应用程序,我也使用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应用程序的实体框架中的数据将不会更新,直到我重新启动应用程序(似乎是一些缓存机制) EF)。

-

但是,如果我删除了InSingletonScope,我将从EF中随机获取错误说:

  

IEntityChangeTracker的多个实例

无法引用实体对象

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

我对依赖注入的理解仍然非常有限,所以有人可以提供建议吗?

-

编辑:我已尝试更改为InRequestScope进行所有进样,但我仍在

  

IEntityChangeTracker的多个实例

无法引用实体对象

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

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

4 个答案:

答案 0 :(得分:3)

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

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

修改

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

public class AccountService : IAccountService
{
    protected readonly DbContext context;

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

    ...
}

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

答案 1 :(得分:1)

我终于使用InRequestScope代替InSingletonScope设法解决了这个问题。

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

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

-

如果你还在面对

  

IEntityChangeTracker的多个实例

无法引用实体对象
更改为InRequestScope后出现

错误,请确保您的实体不会以某种方式缓存或存储以供后续HTTP请求使用。

答案 2 :(得分:1)

可以配置包括lifetime在内的某些服务的DbContext

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

REF

答案 3 :(得分:0)

Dan,当您为整个应用程序设置单个DBContext时,您正在创建瓶颈。在幕后,Entity Framework将相当有效地处理您需要的对象数量。如果你深入到内部,那么联系数据库的实际对象也会做同样的事情。因此,通过制作单例进行优化的尝试实际上可能会产生一个非常大的问题。