释放Entity Framework上下文对象是否必需

19

我们在WCF服务方法中使用Entity Framework与数据库进行通信,最近我们在服务代码上运行了代码审查工具。像往常一样,我们得到了许多审查建议和评论,其中许多评论建议处理Entity Framework的上下文对象。所以我的问题是,如果我在方法内部使用一个Entity Framework上下文对象,当我退出该方法时,GC不会清理该上下文对象吗?我们需要显式地处理上下文对象吗?


你现在怎么使用它?我通常在 using 块内使用上下文。 - GrandMasterFlush
目前它没有使用代码块。 - Abhinay
1
不要使用using语句,因为它可能会在线程启动之前释放上下文,从而终止潜在的线程。 - Thomas Andreè Wang
我认为很多答案都忽略了一个关键点,就是DBContext经常与DependencyInjection(在MVC中)一起使用。在这种情况下,DBContext不是由服务类创建的,而是由框架注入的。因此,在服务类中不应该对其进行处理,因为它不是在该类内创建的。 - shelbypereira
5个回答

31
简单来说:DbContext实现了IDisposable接口,因此你应该在使用完后手动释放它。
虽然你不必手动释放它,因为GC最终会收集它,但是GC是不确定的:你永远不知道“最终”是什么时候。直到它被释放,它将持有未使用的资源-例如,它可能仍然保持着打开的数据库连接。这些资源在GC运行之前不会被释放,除非你手动释放。根据具体细节,你可能会发现自己阻塞了网络资源、文件访问,并且肯定会保留比需要更多的内存。
还有一个潜在的问题:当您手动释放对象时,GC通常不需要调用该对象的Finalizer(如果有)。如果您让GC自动处理带有Finalizer的对象,它会将对象放入Finalizer队列,并自动提升对象到下一个GC代。这意味着带有finalizer的对象将始终存在比其需要更长的时间,然后才被GC回收(因为连续的GC代收集频率较低)。 DBContext很可能属于此类别,因为底层数据库连接是非托管代码。
(参考链接:参考。)

8
这个问题是关于垃圾收集和IDisposable的目的,还是具体关于DbContext吗? - Sergey Berezovskiy
这个问题特定于 DbContext,但答案是 DbContext 受到与每个其他 IDisposable 相同的最佳实践的影响,原因也完全相同 - 因此大多数情况下都是通用答案。 - Dan Puzey
3
这取决于发帖者和点赞这篇答案的人。我在这里没有看到任何与DbContext有关的具体内容,也没有解释哪些资源应该被释放。 - Sergey Berezovskiy
1
我不理解您的反对意见。针对 OP 的具体问题,答案是:是的,GC 将处置 DbContext,但您不知道何时操作会发生(正如我第二段开头所述),而且是的,您应该显式释放(正如我第一句所述)。回答的其余部分是背景和详细信息,以解释为什么这很重要(对于 任何 IDisposable)。 DbContext 的具体细节并不特别相关于答案,因为它们不会改变答案(并且是黑盒子代码的实现细节) 。 - Dan Puzey
5
实际上,根据设计,您似乎不需要处理DBcontext对象。http://blog.jongallant.com/2012/10/do-i-have-to-call-dispose-on-dbcontext.html#.U6WdzrGEeTw - Thomas Andreè Wang

10

我认为最好的方法是在using语句中编写代码。

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

所以它被自动处理掉了。


2
如果我们采用这种方法,如何模拟DBContext以编写单元测试? - Mitch
查找存储库和工作单元模式,请访问以下链接:http://www.asp.net/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application - Chris
2
如果我想使用上下文类,该怎么办?(在构造函数中创建它 - 如何关闭它以及在哪里关闭它?) - Estevez
避免创建新的上下文(https://dev59.com/VWkw5IYBdhLWcg3wBl-A) - Javier Cañon

3
一般来说,如果某个东西实现了IDisposable接口,当你使用完毕后明确地释放它是一个好习惯。尤其是当你不拥有该对象的实现时,你应将其视为黑盒子。此外,即使现在没有必要释放它,在未来也可能需要。
因此,我认为是否「需要」显式释放该对象的问题是无关紧要的。如果它需要被释放——因为实现了IDisposable接口——那么就应该释放它。

2
DBContext的推荐做法是根本不要处理它(在大多数情况下,这是规则的例外),即使它是一个可处理的对象。
问题的一个例子,第一个例子在使用语句中接收调用并对其进行评估,而第二个例子在之后进行评估。(第一个运行,第二个抛出错误“无法完成操作,因为DbContext已被处理。”)
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

2
没有必要显式地处理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;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接