在 Repository 中使用时 DbContext 何时被垃圾收集或处置?
when DbContext is garbage-collected or disposed when using in Repository?
我已经实现了存储库模式,并且在存储库中,我在构造函数中添加了 dbContext,如下所示。使用static是有原因的。我研究的时候,不建议在Context中使用static。
我理解其中的大部分,但是当上下文被处理时我没有理解,就好像我把它当作静态的一样,它不是由垃圾收集器处理的。那么什么时候处理呢?
HTTP 请求何时完成?
还是在应用程序关闭之前它还活着?
private static DBContext _context;
public OrderRepository(DbContext context)
{
_context = context;
}
静态对象将一直存在到程序结束。
但是,您应该担心的不是静态部分,而是 IDispose 部分。
您的 DbContext 在您的程序结束之前不会被释放。这是否是一个问题,取决于其他人是否会连接到数据库,以及您的程序会持续多长时间 运行.
如果您的程序只有 运行 几秒钟,那么如果数据库连接在这几秒钟内保持活动状态就不会成为大问题。
不过请注意,除了数据库连接之外,还有一个 ChangeTracker。
每当您查询完整的实体(=完整的 table 行)时,原始值和获取项目的副本将被放入 ChangeTracker。您将获得对此副本的引用。每当您更改所获取项目的属性值时,这些更改将出现在 ChangeTracker 中的副本中。
当您调用 SaveChanges
时,会将副本与原始文件进行比较以确定必须更新哪些 属性 个值。
如果您让 DbContext 保持活动状态很长一段时间,并且您获取了很多项目,那么您将拥有一个填充了很多项目的 ChangeTracker。
此外,如果您使用Find
通过主键获取项目,那么DbContext将首先检查该项目是否已经在ChangeTracker中。
所以除了ChangeTracker的庞大内容导致的性能问题,你也不会获取到最新的数据库值。
如果别人更新了一个Customer而你获取了同一个Customer,那么这取决于你是否已经在几个小时前获取了这个Customer,你获取的是哪个Customer:你获取的旧的未更新的Customer在客户更新之前,或者新更新的客户,因为你还没有获取这个客户?您确定要跟踪自启动程序以来您获取了哪些客户吗?如果你不这样做,你将永远不知道你得到的是几个小时前获取的客户,还是最新更新的版本。
这些问题已经够多了,可以通过让 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();
}
}
等等
我已经实现了存储库模式,并且在存储库中,我在构造函数中添加了 dbContext,如下所示。使用static是有原因的。我研究的时候,不建议在Context中使用static。 我理解其中的大部分,但是当上下文被处理时我没有理解,就好像我把它当作静态的一样,它不是由垃圾收集器处理的。那么什么时候处理呢? HTTP 请求何时完成? 还是在应用程序关闭之前它还活着?
private static DBContext _context;
public OrderRepository(DbContext context)
{
_context = context;
}
静态对象将一直存在到程序结束。
但是,您应该担心的不是静态部分,而是 IDispose 部分。
您的 DbContext 在您的程序结束之前不会被释放。这是否是一个问题,取决于其他人是否会连接到数据库,以及您的程序会持续多长时间 运行.
如果您的程序只有 运行 几秒钟,那么如果数据库连接在这几秒钟内保持活动状态就不会成为大问题。
不过请注意,除了数据库连接之外,还有一个 ChangeTracker。
每当您查询完整的实体(=完整的 table 行)时,原始值和获取项目的副本将被放入 ChangeTracker。您将获得对此副本的引用。每当您更改所获取项目的属性值时,这些更改将出现在 ChangeTracker 中的副本中。
当您调用 SaveChanges
时,会将副本与原始文件进行比较以确定必须更新哪些 属性 个值。
如果您让 DbContext 保持活动状态很长一段时间,并且您获取了很多项目,那么您将拥有一个填充了很多项目的 ChangeTracker。
此外,如果您使用Find
通过主键获取项目,那么DbContext将首先检查该项目是否已经在ChangeTracker中。
所以除了ChangeTracker的庞大内容导致的性能问题,你也不会获取到最新的数据库值。
如果别人更新了一个Customer而你获取了同一个Customer,那么这取决于你是否已经在几个小时前获取了这个Customer,你获取的是哪个Customer:你获取的旧的未更新的Customer在客户更新之前,或者新更新的客户,因为你还没有获取这个客户?您确定要跟踪自启动程序以来您获取了哪些客户吗?如果你不这样做,你将永远不知道你得到的是几个小时前获取的客户,还是最新更新的版本。
这些问题已经够多了,可以通过让 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();
}
}
等等