
[英]How do I correctly dispose a Linq to SQL DataContext in a Repository?
[英]How do I correctly manage the disposing of a DataContext?
我有一个非常重视数据库访问的Web服务。 它在测试中运行良好,但是一旦我将其投入生产并增加了负载,它就会开始消除当有人在DataContext中调用方法时引发的错误。 该错误通常是以下之一:
你调用的对象是空的
无法访问已处置的对象。 对象名称:“在Dispose之后访问DataContext”。
但不总是。
任何单个Web服务请求都可以导致多达10或15个数据库查询以及1或2个更新。
我已经用数据访问层设计了我的应用程序,数据访问层是一堆对象,这些对象代表数据库中包含所有业务逻辑的表。 这是我的Web服务的一个单独项目,因为它与Web GUI共享。
数据访问对象从具有GetDataContext()
方法的基类派生,该基类在需要时可以启动数据上下文的实例。
在我所有的数据访问对象中,我都这样写:
using (db = GetDataContext())
{
// do some stuff
}
它为每次数据库交互都愉快地创建/使用/配置了我的DataContext(由sqlmetal.exe创建)对象。
经过数小时的头部抓挠后,我认为我的错误原因是在负载下创建和处理了太多数据上下文对象,并且我需要更改某些内容以在相同的时间内共享同一数据上下文。 Web服务请求。
我在互联网上找到了这篇文章 , 这篇文章的DataContextFactory似乎完全可以满足我的需求。
但是,既然我已经实现了这一点,并且DataContext被另存为HttpContext中的一项,我得到...
无法访问已处置的对象。
对象名称:“在Dispose之后访问DataContext”。
...每当我的datacontext被多次使用时。 这是因为我的using (...) {}
代码是在第一次使用我的datacontext后对其进行处理的。
因此,我的问题是...在遍历整个数据访问层并删除使用负载usings
,执行此操作的正确方法是什么? 我不想因为使用而导致内存泄漏,但是同时我想在不同的数据访问对象之间共享数据usings
。
我应该只删除usings
,并在从Web服务请求返回之前手动调用dispose方法吗? 如果是这样,那我该怎么做才能确保牢记所有内容,所以我有几个可能会变得混乱的try-catch
块。
还有另一种更好的方法吗? 我是否应该忘记处理并希望所有内容都被隐式清理?
更新
这个问题似乎不是性能问题……请求处理速度非常快,最多不超过200毫秒。 实际上,我已经通过生成许多没有问题的假请求对它进行了负载测试。
据我所知,它与负载有关,原因有两个:
当问题确实发生时,应用程序池将进入不良状态,并且需要进行回收以使其再次运行。
尽管我更喜欢使用using
的工作单元方法,但有时它并不总是适合您的设计。 理想情况下,您需要确保在完成SqlConnection
释放它们,以便anothe请求有机会从池中获取该连接。 如果这不可能,那么您需要确保在每次请求后都会处理上下文。 这可以通过以下两种方法完成:
如果您使用的是WebForms,则可以在页面生命周期的末尾捆绑处理DataContext
。 检查HttpContext.Items
集合,以确定最后一页是否具有数据上下文,如果有,请对其进行处理。
创建一个专用的IHttpModule
,它将一个事件附加到请求的末尾,您在此处执行与上述相同的操作。
上面两种解决方案的问题是,如果您承受着沉重的负担,您会发现许多请求挂起,等待连接可用,可能会超时。 您必须权衡风险。
总而言之,工作单元方法仍将受到青睐,因为您将在不再需要资源时立即释放它。
我自己解决了这个问题...
我有一个具有可创建DataContext实例的方法的基类,如下所示:
public abstract class MyBase {
protected static DataContext db = null;
protected static DataContext GetDataContext() {
return new DataContext("My Connection String");
}
// rest of class
}
然后,在继承了MyBase的类(我想在其中进行查询)中,我得到了如下语句:
using (db = GetDataContext()) { ... }
事实是,我想同时从静态方法和非静态方法访问数据库,因此在我的基类中,我将db
变量声明为静态...大错误!
如果将DataContext变量声明为静态变量,则在繁重的工作量中,同时发生很多事情的同时,请求之间共享了DataContext,并且如果在同一时间在DataContext上发生了某些事情,则它会破坏DataContext的实例,以及存储在应用程序池中的数据库连接,供所有后续请求使用,直到被回收为止,并刷新数据库连接。
因此,简单的解决方法是更改此设置:
protected static DataContext db = null;
对此:
protected DataContext db = null;
...这将破坏静态方法中的所有using
语句。 但这可以通过在using
声明DataContext变量来轻松解决,如下所示:
using (DataContext db = GetDataContext()) { ... }
例如,如果您有一个引用另一个对象的对象(即,两个表之间的联接),并且在上下文被处置后尝试访问该引用的对象,则会发生这种情况。 像这样:
IEnumerable<Father> fathers;
using (var db = GetDataContext())
{
// Assume a Father as a field called Sons of type IEnumerable<Son>
fathers = db.Fathers.ToList();
}
foreach (var father in fathers)
{
// This will get the exception you got
Console.WriteLine(father.Sons.FirstOrDefault());
}
可以通过强制它加载所有引用的对象来避免这种情况,如下所示:
IEnumerable<Father> fathers;
using (var db = GetDataContext())
{
var options = new System.Data.Linq.DataLoadOptions();
options.LoadWith<Father>(f => f.Sons);
db.LoadOptions = options;
fathers = db.Fathers.ToList();
}
foreach (var father in fathers)
{
// This will no longer throw
Console.WriteLine(father.Sons.FirstOrDefault());
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.