是否需要手动执行DataContext的Dispose方法?
2011-05-12 14:04
351 查看
我们知道DataContext实现了IDisposable接口。在C#中,凡是实现了IDisposable接口的类,都推荐的使用using语句。如下:
使用using语句可以确保以正确的方式调用Dispose方法,即使在语句块中出现异常,Dispose方法也将被执行。
但当我们使用如下代码时,将不可避免地得到“System.ObjectDisposedException: 无法访问已释放的对象”异常:
由于延迟加载的特性,LINQ to SQL其实并没有真正查询数据库,而会将实际查询放到遍历时才进行(在Table.GetEnumerator方法内部调用SqlProvider的 Execute方法)。而此时DataContext早已Dispose,自然无法访问。
解决此问题有两种方法:
GetProductsByPrice方法返回时执行ToList方法,这将立即执行查询。
不手动Dispose。这样将会在遍历的时候执行查询。
使用方法1等于摒弃了延迟查询的优势,而使用方法2,是否会对系统造成过多的负载呢?
对此,我翻阅了一些资料,发现尽管有的支持手动Dispose的方式,但更多的则认为没有必要这么做:
Linq DataContext and Dispose
About Disposing the DataContext
ASP.NET MVC Tip #34 – Dispose of Your DataContext (or Don’t)
我们用Reflector打开DataContext,可以看到在其Dispose方法中调用了SqlProvider的Dispose方法。而 SqlProvider.Dispose方法主要任务是关闭数据库连接(调用 SqlConnectionManager.DisposeConnection方法,再跟下去可以发现实际上最终是调用了 SqlConnection.Close方法),剩下的无论是在DataContext还是SqlProvider的Dispose方法中,都只是将一些对象置为null。
而DataContext其实已经将数据连接的打开和关闭管理得井井有条了。在DataContext.SubmitChanges方法中可以看到,在finally块中调用了SqlConnection.Close方法。而负责执行查询的DataContext.ExecuteQuery方法跟踪到最后也会在SqlProvider.Execute方法的finally块中调用SqlConnectionManager的 ReleaseConnection方法。也就是说在我们手动Dispose DataContext的时候,其实主要工作早已经执行完了,剩下的只是清空一些对象所占用的内存,使它们尽早被GC回收。除此之外,DataContext.Dispose再没有其他好处了。并且我们会发现SqlConnectionManager的 ReleaseConnection方法所执行的内容甚至比CloseConnection还要多。
因此我们得出结论,在使用LINQ to SQL时,完全没有必要手动执行DataContext的Dispose方法,更没有必要使用using语句。
using (DataContext db = new DataContext(fileOrServerOrConnection)) { //... }
使用using语句可以确保以正确的方式调用Dispose方法,即使在语句块中出现异常,Dispose方法也将被执行。
但当我们使用如下代码时,将不可避免地得到“System.ObjectDisposedException: 无法访问已释放的对象”异常:
static void Main() { var products = GetProductByPrice(20); foreach (var p in products) { // ... } } private static IEnumerable<Product> GetProductsByPrice(decimal price) { using (NorthwindDataContextDataContext db = new NorthwindDataContextDataContext()) { var product = from p in db.Products where p.UnitPrice >= price select p; return product; } }
由于延迟加载的特性,LINQ to SQL其实并没有真正查询数据库,而会将实际查询放到遍历时才进行(在Table.GetEnumerator方法内部调用SqlProvider的 Execute方法)。而此时DataContext早已Dispose,自然无法访问。
解决此问题有两种方法:
GetProductsByPrice方法返回时执行ToList方法,这将立即执行查询。
不手动Dispose。这样将会在遍历的时候执行查询。
使用方法1等于摒弃了延迟查询的优势,而使用方法2,是否会对系统造成过多的负载呢?
对此,我翻阅了一些资料,发现尽管有的支持手动Dispose的方式,但更多的则认为没有必要这么做:
Linq DataContext and Dispose
About Disposing the DataContext
ASP.NET MVC Tip #34 – Dispose of Your DataContext (or Don’t)
我们用Reflector打开DataContext,可以看到在其Dispose方法中调用了SqlProvider的Dispose方法。而 SqlProvider.Dispose方法主要任务是关闭数据库连接(调用 SqlConnectionManager.DisposeConnection方法,再跟下去可以发现实际上最终是调用了 SqlConnection.Close方法),剩下的无论是在DataContext还是SqlProvider的Dispose方法中,都只是将一些对象置为null。
而DataContext其实已经将数据连接的打开和关闭管理得井井有条了。在DataContext.SubmitChanges方法中可以看到,在finally块中调用了SqlConnection.Close方法。而负责执行查询的DataContext.ExecuteQuery方法跟踪到最后也会在SqlProvider.Execute方法的finally块中调用SqlConnectionManager的 ReleaseConnection方法。也就是说在我们手动Dispose DataContext的时候,其实主要工作早已经执行完了,剩下的只是清空一些对象所占用的内存,使它们尽早被GC回收。除此之外,DataContext.Dispose再没有其他好处了。并且我们会发现SqlConnectionManager的 ReleaseConnection方法所执行的内容甚至比CloseConnection还要多。
因此我们得出结论,在使用LINQ to SQL时,完全没有必要手动执行DataContext的Dispose方法,更没有必要使用using语句。
相关文章推荐
- 是否需要手动执行DataContext的Dispose方法?
- 是否需要手动执行DataContext的Dispose方法?
- 是否需要手动执行DataContext的Dispose方法?
- DirectX 3D中某些对象的释放需要手动调用Dispose方法
- Linux安装MySQL的两种方法{linux系统mysql安装之前需要先检查是否已经安装,把已经有的库文件卸载掉,否则会出现覆盖错误}
- 方法中使用到的NSString是否需要dealloc?
- 在非ARC项目中引用ARC对象,是否需要手动释放
- Struts2中Action中是否需要实现Execute方法
- 判断某个方法是否没执行
- 检查页面Session是否过期,过期执行相应操作 解决方法
- Android应用程序是否需要手动退出
- linux系统更新正在运行进程的可执行文件需要注意的text file busy的原因及解决方法
- SQLiteDatabase 是否需要调用close()方法?什么时候调用?
- 在堆中分配空间,需要手动delete才会执行析构函数.
- 【centos安装wordpress】要执行请求的操作,WordPress 需要访问您网页服务器的权限。 请输入您的 FTP 登录XXXX”完美解决方法
- 方法中使用到的NSString是否需要dealloc?
- Content Deployment执行之前是否需要开启feature? 安装dll到GAC?
- 放在UserIdentity的State集合中的东西是否需要手动清除?
- 活动a 使用 启动为结果 方法 启动 活动 b, b什么都不做 并返回给a,a中的 在活动结果时候 回调 是否被执行?
- 方法一 Java如何判断线程池所有任务是否执行完毕