c# - 实体框架 dbcontext c# 的垃圾收集
问题描述
只是想知道我是否在这里正确处理了我的 dbcontext 对象,还是应该使用 using 块?
public class RepoBankAccount : IBankAccount
{
private AppDbContext db = null;
public RepoBankAccount()
{
this.db = new AppDbContext();
}
public RepoBankAccount(AppDbContext db)
{
this.db = db;
}
public IEnumerable<BankAccount> ViewAllBankAccount()
{
return db.BankAccounts.ToList();
}
public BankAccount ViewBankAccount(long accountNumber)
{
return db.BankAccounts.Where(b => b.AccountNumber.Equals(accountNumber)).SingleOrDefault();
}
public void DeleteBankAccount(BankAccount bankAccount)
{
db.BankAccounts.Remove(bankAccount);
Save();
}
public void InsertBankAccount(BankAccount bankAccount)
{
db.BankAccounts.Add(bankAccount);
Save();
}
public void Save()
{
try
{
db.SaveChanges();
}
catch(Exception ex)
{
System.Console.WriteLine("Error:" + ex.Message);
}
finally
{
if(db != null)
db.Dispose();
}
}
}
我读到我不应该手动调用 dispose
但是在一些示例代码中,我也注意到了这个脚手架代码,但不太清楚它是如何独立完成这项工作的。
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
解决方案
DbContexts 被设计为短暂的。DbContext 的第一次初始化和使用提出了解决实体映射的加速成本,但除此之外,上下文可以限定为单个调用或一组调用。您的代码将正常工作,只要您的 repo 被处理,dbContext 就会被清理。虽然这种方法存在缺陷,但随着产品的成熟,很容易忘记处置某些东西,而且如果这些 DbContexts 长期存在,它们可以吸收相当多的内存。
为避免与 DbContext 断开连接的实体出现问题,实体不应离开其 DbContext 的范围。如果是这样,例如,如果触发了延迟加载,您就会遇到错误。
例如,假设我在控制器中有一个方法或类似的方法:(注意:我不主张将实体返回到视图,但例如,为了......)
public ActionResult View(long accountNumber)
{
BankAccount bankAccount;
using (var repo = new RepoBankAccount())
{
bankAccount = repo.ViewBankAccount(accountNumber);
}
return new View(bankAccount);
}
回购将被处置,如果银行账户没有引用,或者所有引用都被急切加载,这个调用就可以正常工作。但是,如果有延迟加载调用,控制器方法将失败,因为与银行帐户关联的 DbContext 已被释放。
这可以通过确保返回发生在 using 块的范围内来补偿:
public ActionResult View(long accountNumber)
{
using (var repo = new RepoBankAccount())
{
BankAccount bankAccount = repo.ViewBankAccount(accountNumber);
return new View(bankAccount);
}
}
为了帮助避免此类问题,通常最好创建 POCO 视图模型类以从实体填充到 DbContext 范围内,然后返回这些视图模型。毫不奇怪的延迟加载命中等。
当您想要跨实体协调更新等事情以确保更新被提交或回滚时,这真正开始崩溃的地方。您的每个 repo 类都将具有单独的 DbContext 实例。
熟悉解决此问题的第一个默认方法是依赖注入和控制反转,尤其是 IoC 容器,例如Autofac、Unity、Ninject 或 Castle Windsor。使用这些,您可以让您的存储库类接受对 DbContext 的依赖,并且它们可以在整个生命周期中限定一个 Dependency 实例。(例如每个 HTTP 请求)这样,单个会话调用中所有存储库的引用都将提供相同的 DbContext 实例。调用 SaveChanges() 将尝试提交所有挂起的更改。
更好的模式是工作单元模式,其中 DbContext 的范围被移到存储库之外,并且每个存储库都提供对 DbContext 的引用,或者可以找到它。(类似于 IoC 模式的工作方式)UoW 模式的优点是您可以将提交/回滚的控制权转移给存储库的使用者我提倡使用 Mehdime 的 DbContextScope,因为它不需要传递对UoW/DbContext。 Mehdime DbContextScope (EF6 original github ) EFCore 支持的端口
推荐阅读
- amazon-ec2 - 使用 AWS 实例集群的本地 RabbitMQ
- regex - 非贪婪的正则表达式
- c# - 将面板放置在具有屏幕坐标的矩形中
- r - R中的随机数生成没有连续重复
- .htaccess - 将 HTTP 重定向到 HTTPS,但仅将通配符子域重定向到 HTTP
- c# - 如果用户尝试在当前行 C# 的前列中选择一个单元格,如何停止验证 datagridview 单元格
- python - 为什么 mypy 不承认 Mapping.get() 的参数只是位置的?
- python - 是否可以在 pyspark 中转换数据框的多列?
- memory - 库和可执行文件的基地址和大小
- python - 将列表中的一个元素替换为相邻位置的另一个元素