我们在WCF服务方法中使用实体框架与数据库进行通信,最近我们在服务代码上运行代码审查工具。像往常一样,我们通过工具获得了许多审核提案,许多评论意见建议处置实体框架上下文对象。所以,我的问题是,如果我在方法中使用实体框架上下文对象,一旦我退出该方法,GC不会清理上下文对象?我们需要显式处理上下文对象吗?
答案 0 :(得分:27)
简单地说:DbContext
实施IDisposable
,因此您应该在完成后立即手动处理它。
你不需要处理它,因为GC最终会收集它,但GC不是确定性的:你永远不知道“最终”何时会。在它被处理之前,它将保留未使用的资源 - 例如,它可能仍然具有开放的数据库连接。 GC运行之前不会释放这些资源,除非您手动处理。根据具体细节,您可能会发现您不必要地阻止了网络资源,文件访问,并且您肯定会保留比您需要的更多内存。
还有一个潜在的打击:当你手动处理一个对象时,GC通常不需要在该对象上调用Finalizer(如果有的话)。如果让GC自动处理带有Finalizer的对象,它会将对象放在Finalizer Queue中 - 并自动将对象提升到下一代GC生成。这意味着具有终结器的对象将始终以比GCed之前所需的数量级更长的数量级挂起(因为不太频繁地收集连续的GC生成)。 DBContext
可能属于此类别,因为底层数据库连接将是非托管代码。
(有用的reference。)
答案 1 :(得分:10)
我认为最好的方法是在使用声明中编码
using(var cx = new DbContext())
{
//your stuff here
}
因此它被自动处理
答案 2 :(得分:3)
一般情况下,如果某事实施IDisposable
,那么当你通过时,明确处理它是一个好主意(TM)。如果您不拥有所述对象的实现,则尤其如此;在这种情况下,你应该把它当作一个黑盒子。此外,即使现在不一定“需要”处理它,也可能是将来。
因此,恕我直言,你是否“需要”明确处置该对象的问题是无关紧要的。如果它要求被处置 - 由于实施IDisposable
- 它应该被处置掉。
答案 3 :(得分:2)
建议使用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);
}
永远不会处置。因为它会在大多数情况下照顾好自己,就像它设计的那样。
现在你应该强行打开一个连接然后上下文在转移完成时不会自动关闭它,因为它不知道什么时候你必须/应该/应该处置对象或关闭连接并保持连接对象未披露。
额外的午夜阅读:
答案 4 :(得分:1)
不需要显式处理DbContext。
这是DbContext之前的工具的旧版本。 DbContext是托管代码,乐观地自己维护数据库连接。为什么用大锤呢?快点什么?为什么不让垃圾收集器决定在机器空闲或需要内存时清理的最佳时间?另请参阅这篇文章:https://blog.jongallant.com/2012/10/do-i-have-to-call-dispose-on-dbcontext/
不用担心必须处理,可以简化和优化您的代码。通常,我可能会从数据库“帮助程序”类继承到使用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;
}
}