繁体   English   中英

是否需要处置实体框架上下文对象

[英]Is Disposing of Entity Framework context object required

我们在WCF服务方法中使用实体框架与数据库进行通信,最近我们在服务代码上运行代码审查工具。 像往常一样,我们通过工具获得了许多审核提案,许多评论意见建议处置实体框架上下文对象。 所以,我的问题是,如果我在方法中使用实体框架上下文对象,一旦我退出该方法,GC不会清理上下文对象? 我们需要显式处理上下文对象吗?

简单地说: DbContext实现了IDisposable ,因此您应该在完成后立即手动处理它。

不需要处理它,因为GC最终会收集它,但GC不是确定性的:你永远不知道什么时候会“最终”。 在它被处理之前,它将保留未使用的资源 - 例如,它可能仍然具有开放的数据库连接。 除非您手动处理, 否则在GC运行之前不会释放这些资源。 根据具体细节,您可能会发现您不必要地阻止了网络资源,文件访问,并且您肯定会保留比您需要的更多内存。

还有一个潜在的打击:当你手动处理一个对象时,GC通常不需要在该对象上调用Finalizer(如果有的话)。 如果让GC自动处理带有Finalizer的对象,它会将对象放在Finalizer Queue中 - 并自动将对象提升到下一代GC生成。 这意味着具有终结器的对象将始终以比GCed之前所需的数量级更长的数量级挂起(因为不太频繁地收集连续的GC生成)。 DBContext可能属于此类别,因为底层数据库连接将是非托管代码。

(有用的参考 。)

我认为最好的方法是在using语句中对其进行编码

using(var cx = new DbContext())
{
  //your stuff here
}

所以它得到了自动处理

一般来说,如果某些东西实现了IDisposable ,那么当你通过时,明确处理它是一个好主意(TM)。 如果您不拥有所述对象的实现,则尤其如此; 在这种情况下,你应该把它当作一个黑盒子。 另外,即使现在不一定“需要”处理它,它可能在将来。

因此,恕我直言,你是否“需要”明确处置该对象的问题是无关紧要的。 如果要求处置 - 由于实施IDisposable - 它应该被处置。

建议使用DBContext的方法是根本不处理它(在大多数情况下它是规则的例外),即使它是一次性对象。

问题的一个例子,第一个例子是在using语句中进行调用并对其进行评估,而第二个例子是在之后对其进行评估。 (第一个ons运行,第二个抛出错误The operation cannot be completed because the DbContext has been disposed.

List<Test> listT;
using (Model1 db = new Model1())
{
    listT = db.Tests.ToList(); //ToList Evaluates
}
foreach (var a in listT)
{
    Console.WriteLine(a.value);
}

IEnumerable<Test> listT1;
using (Model1 db = new Model1())
{
    listT1 = db.Tests;
}
foreach (var a in listT1) //foreach evaluates (but at wrong time)
{
    Console.WriteLine(a.value);
}

同样的问题发生在

IEnumerable<Test> listT1;
Model1 db = new Model1();
listT1 = db.Tests;
db.Dispose();
foreach (var a in listT1) //foreach evaluates (but at wrong time)
{
    Console.WriteLine(a.value);
}

只要您不手动打开连接,只需使用即可安全使用

IEnumerable<Test> listT1;
Model1 db = new Model1();
listT1 = db.Tests;
foreach (var a in listT1) //foreach evaluates (but at wrong time)
{
    Console.WriteLine(a.value);
}

永远不要处置。 因为它会在大多数情况下照顾好自己,就像它设计的那样。

现在,如果您通过强制打开连接,则上下文不会在传输完成时自动关闭它,因为它不知道何时然后您必须/应该/应该处置该对象或关闭连接并保持对象未公开。

额外的午夜阅读:

  1. http://blog.jongallant.com/2012/10/do-i-have-to-call-dispose-on-dbcontext.html#.U6WdzrGEeTw
  2. https://msdn.microsoft.com/en-us/data/jj729737.aspx

无需显式处置DbContext。

这是来自前DbContext工具的旧版本。 DbContext是托管代码,并且乐观地维护数据库连接。 为什么大锤呢? 什么时候赶时间? 为什么不让垃圾收集器决定在机器空闲或需要内存时清理的最佳时间? 另请参阅这篇文章: https//blog.jongallant.com/2012/10/do-i-have-to-call-dispose-on-dbcontext/

不必担心必须处理将简化和优化您的代码。 通常我可以从数据库“helper”类继承到我使用getter返回已经存在的DbContext实例或实例化新实例的地方。

public class DataTools
{
    private AppContext _context;
    protected AppContext Context => _context ?? (_context = new AppContext());
}

pubic class YourApp : DataTools
{
    public void DoLotsOfThings()
    {
        var = Context.SomeTable.Where(s => s.....);
        var stuff = GetSomeThing();
       foreach(){}
    }

    Public string GetSomething()
    {
        return Context.AnotherTable.First(s => s....).Value;
    }
}

暂无
暂无

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

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