简体   繁体   English

实体框架dbcontext C#的垃圾收集

[英]Garbage collection for Entity Framework dbcontext c#

just wondering if I dispose my dbcontext object correctly here or should I be using the using block instead? 只是想知道我是否在这里正确放置了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();
        }

    }        
}

I read that I should not be calling dispose manually from 我读到我不应该从

https://softwareengineering.stackexchange.com/questions/359667/is-it-ok-to-create-an-entity-framework-datacontext-object-and-dispose-it-in-a-us https://softwareengineering.stackexchange.com/questions/359667/is-it-ok-to-create-an-entity-framework-datacontext-object-and-dispose-it-in-a-us

But in some sample code, I also notice this scaffolding code but not too clear how it does the job on its own. 但是在一些示例代码中,我也注意到了这个脚手架代码,但是并不太清楚它是如何独立完成工作的。

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            db.Dispose();
        }
        base.Dispose(disposing);
    }

DbContexts are designed to be short-lived. DbContext被设计为短命的。 The very first initialization and use of a DbContext presents a spin up cost to resolve the entity mappings, but aside from that the context can be scoped to individual calls, or sets of calls. 最初的初始化和DbContext的使用会带来解决实体映射的费用增加,但除此之外,上下文可以限定为单个调用或一组调用。 Your code will work fine and so long as your repo is disposed, the dbContext will be cleaned up. 您的代码可以正常工作,并且只要处置您的存储库,dbContext就会被清理。 There are pitfalls with this approach though in that as the product matures it is easy to forget to dispose something, and these DbContexts can soak up a fair bit of memory if they are long-lived. 这种方法存在一些缺陷,尽管随着产品的成熟,很容易忘记处理某些东西,而且这些DbContext可以长期保存很多内存。

To avoid issues with entities that become disconnected from their DbContext, an entity should never leave the scope of it's DbContext. 为了避免实体与其DbContext断开连接的问题,实体永远不应离开其DbContext的范围。 If it does, you run into errors if a lazy load gets triggered for example. 如果是这样,例如,如果触发了惰性加载,就会遇到错误。

For instance lets say I have a method in a Controller or such that does something like this: (Note: I don't advocate ever returning Entities to a view, but for example's sake...) 例如,假设我在Controller中有一个方法或执行以下操作的方法:(注意:我不提倡将Entities返回到视图中,但是例如,为了...)

public ActionResult View(long accountNumber)
{
   BankAccount bankAccount;
   using (var repo = new RepoBankAccount())
   {
      bankAccount = repo.ViewBankAccount(accountNumber);
   }
   return new View(bankAccount);
}

The repo will be disposed, and if bank account either has no references, or all references are eager loaded, this call would work just fine. 回购将被处置,并且如果银行帐户没有参考资料,或者渴望加载所有参考资料,则此调用可以正常进行。 However, if there is a lazy load call, the controller method will fail because the DbContext associated with the Bank Account was disposed. 但是,如果存在延迟加载调用,则控制器方法将失败,因为已处置了与银行帐户关联的DbContext。

This can be compensated for by ensuring the return occurs inside the scope of the using block: 这可以通过确保返回发生在using块的范围内来补偿:

public ActionResult View(long accountNumber)
{
   using (var repo = new RepoBankAccount())
   {
      BankAccount bankAccount = repo.ViewBankAccount(accountNumber);
      return new View(bankAccount);
   }
}

To help avoid issues like this, it is generally a better idea to create POCO view model classes to populate within the scope of the DbContext from the entities, then return those view models. 为了避免此类问题,通常最好创建POCO视图模型类,以在实体的DbContext范围内进行填充,然后返回这些视图模型。 No surprise lazy load hits etc. 没有意外的懒惰负载命中等。

Where this really starts to crumble apart is when you want to coordinate things like updates across entities to ensure that updates are committed or rolled back together. 当您希望协调诸如跨实体的更新之类的事情以确保更新被一起提交或回滚时,这种情况真正开始崩溃的地方。 Each of your repo classes are going to have separate DbContext instances. 您的每个repo类都将具有单独的DbContext实例。

The first default approach to get familiar with to address this is Dependency Injection and Inversion of Control, particularly an IoC container such as Autofac , Unity, Ninject, or Castle Windsor. 解决此问题的第一个默认方法是依赖注入和控制反转,尤其是IoC容器,例如Autofac ,Unity,Ninject或Castle Windsor。 Using these, you can have your repository classes accept a dependency on a DbContext, and they can scope a single instance of a Dependency across a lifetime. 使用这些,您可以使您的存储库类接受对DbContext的依赖关系,并且它们可以在整个生命周期内限定单个依赖关系实例。 (such as per HTTP Request for example) In this way, the references of all of your repositories in a single session call will be provided the same DbContext instance. (例如,按照HTTP请求),这样,将为单个会话调用中所有存储库的引用提供相同的DbContext实例。 A call to SaveChanges() will attempt to commit all pending changes. 调用SaveChanges()将尝试提交所有未决的更改。

A better pattern is the Unit of Work pattern where the scope of the DbContext is moved outside of the repository and each repository is either provided a reference to the DbContext, or can locate it. 更好的模式是“工作单元”模式,其中DbContext的范围移到存储库之外,并且每个存储库都提供了对DbContext的引用,也可以找到它。 (similar to how the IoC pattern works) The advantage of UoW patterns is that you can move control of the commit/rollback out to the consumer of the repositories I promote the use of Mehdime's DbContextScope since it negates the need to pass around references to the UoW/DbContext. (类似于IoC模式的工作方式)UoW模式的优势在于,您可以将提交/回滚的控制权移交给存储库的使用者,因此我提倡使用Mehdime的DbContextScope,因为它不需要传递对DashContextScope的引用。 UOW /的DbContext。 Mehdime DbContextScope (EF6 original github ) EFCore supported Port Mehdime DbContextScopeEF6原始githubEFCore支持的端口

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM