首页 > 解决方案 > 在存储库中使用时 DbContext 何时被垃圾收集或处置?

问题描述

我已经实现了存储库模式,并且在存储库中,我在构造函数中添加了 dbContext,如下所示。使用静态是有原因的。在我研究的时候,不建议在 Context 中使用 static。我理解其中的大部分内容,但在处理上下文时没有得到,就好像我将其设置为静态一样,它不是由垃圾收集器处理的。那么什么时候处理呢?HTTP 请求何时完成?还是在应用程序关闭之前它还活着?

private static DBContext _context;
public OrderRepository(DbContext context)
{
    _context = context;
}

标签: c#entity-frameworkdbcontext

解决方案


静态对象将保持活动状态,直到程序结束。

但是,您应该担心的不是静态部分,而是 IDispose 部分。

在程序结束之前,您的 DbContext 不会被释放。这是否是一个问题,取决于其他人是否会连接到数据库,以及您的程序将运行多长时间。

如果您的程序只运行几秒钟,那么如果数据库连接在这几秒钟之前保持活动状态,那将不是什么大问题。

但请注意,除了数据库连接之外,还有一个 ChangeTracker。

每当您查询完整的实体(= 完整的表行)时,原始值和获取的项目的副本将被放入 ChangeTracker。您将获得对此副本的引用。每当您更改获取项目的属性值时,这些更改将在 ChangeTracker 中的副本中。

当您调用SaveChanges时,会将副本与原始副本进行比较,以确定必须更新哪些属性值。

如果你让你的 DbContext 存活了很长一段时间,并且你获取了很多项目,那么你将拥有一个包含很多项目的 ChangeTracker。

此外,如果您使用Find通过主键获取项目,则 DbContext 将首先检查该项目是否已经在 ChangeTracker 中。

因此,除了 ChangeTracker 的巨大内容导致的性能问题外,您也不会获得已获取项目的最新数据库值。

如果其他人更新了客户并且您获取了相同的客户,那么这取决于您是否已经在几个小时前获取了此客户,您获得了哪个客户:您在客户更新之前获取的旧的未更新客户,或新更新的客户,因为您还没有获取此客户?您确定要跟踪自您启动程序以来您获取的客户?如果您不这样做,您将永远不知道您获得的是几小时前获取的客户,还是最新的更新版本。

这些问题已经足够了,可以通过尽可能短的保持 DbContext 活动来轻松缓解这些问题。添加第二次创建 DbContext 对象相当便宜的论点,我相信您不应该让 DbContext 对象保持比需要的时间更长的时间。

public Customer AddCustomer(...)
{
    using (var dbContext = new MyDbContext())     // or use a factory
    {
        Customer addedCustomer =  dbContext.Customers.Add(...);
        dbContext.SaveChanges();
        return addedCustomer;
    }
}

public ICollection<Customer> QueryCustomerByCity(int CityId)
{
    using (var dbContext = new MyDbContext()) 
    {
        return dbContext.Customers
            .Where(customer => customer.CityId == cityId)
            .ToList();
    }
}

等等


推荐阅读