EF的DbContext的单例作用域

10 浏览
0 Comments

EF的DbContext的单例作用域

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

基本上,目前我是这样在Ninject中注册我的DbContext和Services的。

kernel.Bind().To().InSingletonScope();

kernel.Bind().To().InSingletonScope();

kernel.Bind().To().InSingletonScope();

kernel.Bind().To().InSingletonScope();

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

控制器:

private IAccountService _accountService;

public MemberController(IAccountService accountService)

{

_accountService = accountService;

}

然而,我强烈感觉这种单例范围会在我的Web应用程序中引起问题,特别是对于Entity Framework的上下文而言,因为它是单例的。

我已经因此遇到了一个小问题,如果我使用SQL管理工具手动更新数据库,我的Web应用程序中的Entity Framework数据在我重新启动应用程序之前将不会更新(似乎是EF中的某种缓存机制)。

然而,如果我删除InSingletonScope,我将随机收到来自EF的错误:

引用了IEntityChangeTracker的多个实例中的一个实体对象

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

我对依赖注入的理解还非常有限,所以能否有人给予建议?

编辑:我尝试将所有依赖项的范围更改为InRequestScope,但我仍然收到

引用了IEntityChangeTracker的多个实例中的一个实体对象

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

最终编辑:好的,我找到了问题,是我的缓存机制在缓存之前的请求,导致了所有后续请求中的关系问题。

0
0 Comments

问题的原因是使用Singleton作用域来管理EF的DbContext是一个很糟糕的想法。应该使用Request作用域,因为它在请求的生命周期内就相当于一个单例。

至于为什么在使用Request作用域时会出现错误,我不能确定。假设您使用的所有实体都来自同一上下文类型,并且您在每个需要的地方正确地注入了上下文,就不应该有多个上下文实例。

在重新阅读您的问题后,听起来您的服务实际上是在其构造函数中初始化上下文。如果是这样的话,那就是问题所在。您的上下文应该被注入到您的服务中,例如:

public class AccountService : IAccountService
{
    protected readonly DbContext context;
    public AccountService(DbContext context)
    {
        this.context = context;
    }
    ...
}

然后,Ninject将在实例化任何服务时正确地注入请求作用域的MyApplicationContext

对于Web应用程序,几乎所有的东西都应该是请求作用域。由于控制器等东西在每个请求时都会被实例化和处理,您将始终获得一个新的服务副本,它将在您在应用程序的其他区域之间传递以完成请求时保留下来。

我已经尝试过了,在问题编辑中看看。非常奇怪的问题,有时实体的关系没有被填充(尤其是第一次运行时),变成了null。

0
0 Comments

在ASP.NET应用程序中,将DbContext配置为Singleton范围并不是一个好主意。虽然这样做可以保持服务在请求结束后继续运行,但这样做存在一些问题。为了理解为什么将DbContext配置为Singleton范围是一个坏主意,我们需要了解DbContext的工作原理。

DbContext是Entity Framework中用于与数据库进行交互的主要组件之一。它代表了一个数据库会话,负责管理数据的读取、写入和更改跟踪。在每个请求中,ASP.NET框架将为每个请求创建一个新的DbContext实例,并在请求结束时将其销毁。这样做的好处是,每个请求都有自己的DbContext实例,可以确保数据的隔离性和一致性。

如果将DbContext配置为Singleton范围,则意味着所有请求将共享同一个DbContext实例。这可能导致以下问题:

1. 数据混乱:由于所有请求共享同一个DbContext实例,不同请求之间的数据可能会相互干扰。例如,一个请求可能会更改另一个请求正在使用的数据,导致数据不一致。

2. 内存泄漏:由于DbContext会跟踪更改的实体对象,如果将其配置为Singleton范围,那么在请求结束后,DbContext将继续跟踪这些实体对象。这可能导致内存泄漏,因为这些实体对象无法被垃圾收集器回收。

3. 并发问题:由于所有请求共享同一个DbContext实例,当多个请求同时对数据库进行读写操作时,可能会发生并发问题。这可能导致数据损坏或丢失。

为了避免这些问题,推荐的做法是将DbContext配置为Scoped范围。在每个请求中,ASP.NET框架将为该请求创建一个新的DbContext实例,并在请求结束时将其销毁。这样可以确保每个请求都有自己的DbContext实例,从而保证数据的隔离性和一致性。

如果你需要在请求结束后访问DbContext,而不将其配置为Singleton范围,可以考虑使用依赖注入来获取DbContext实例。在每个需要访问DbContext的类或方法中,通过构造函数或属性注入的方式获取DbContext实例。这样可以在需要的时候获取DbContext实例,并在使用完毕后及时释放。

总之,将DbContext配置为Singleton范围可能导致数据混乱、内存泄漏和并发问题。为了避免这些问题,应将DbContext配置为Scoped范围,并使用依赖注入来获取DbContext实例。这样可以确保每个请求都有自己的DbContext实例,从而保证数据的隔离性和一致性。

0
0 Comments

在使用Entity Framework时,将DBContext设置为整个应用程序的单例模式,会导致出现性能瓶颈。在内部实现中,Entity Framework会自动处理所需的对象数量,非常高效。如果深入研究内部机制,与数据库交互的实际对象也会做相同的优化。因此,将DBContext设置为单例模式的尝试可能实际上会带来很大的问题。

当将DBContext设置为单例模式时,会导致以下问题:

1. 并发性能:多个请求同时访问数据库时,单个DBContext实例无法处理并发请求,可能会导致线程安全问题和性能下降。

2. 数据一致性:在多个请求之间共享同一个DBContext实例时,可能会出现数据一致性问题。如果一个请求修改了数据库中的数据,而另一个请求在此期间读取了同一份数据,就会导致数据不一致。

为了解决这些问题,应将DBContext设置为短暂生命周期的对象,即每个请求或每个操作都创建一个新的DBContext实例,用完即销毁。这样可以保证并发请求的安全性和数据一致性。

以下是将DBContext设置为短暂生命周期的示例代码:

public class SomeService
{
    private readonly MyDbContext _dbContext;
    public SomeService(MyDbContext dbContext)
    {
        _dbContext = dbContext;
    }
    public void DoSomething()
    {
        using (var context = new MyDbContext())
        {
            // perform database operations using the context
        }
    }
}

通过在每个请求或操作中创建一个新的DBContext实例,可以避免并发性能问题和数据一致性问题。每个DBContext实例都是独立的,不会影响其他请求的操作。

总结起来,将DBContext设置为单例模式可能会导致并发性能问题和数据一致性问题。为了解决这些问题,应将DBContext设置为短暂生命周期的对象,每个请求或操作都创建一个新的DBContext实例。这样可以确保并发请求的安全性和数据一致性。

0