SqlConnection SqlCommand SqlDataReader IDisposable
SqlConnection SqlCommand SqlDataReader IDisposable
SqlConnection
、SqlCommand
和SqlDataReader
都实现了IDisposable
接口。我读到了一个最佳实践,即始终将IDisposable
对象包装在using
块中。\n因此,我通常查询数据的场景看起来像这样(当然,在更大的上下文中,像linq2sql这样的映射工具更适合,但让我们假设我们想在这里使用这种方法):\n
using (SqlConnection cn = new SqlConnection("myConnectionstring")) { using (SqlCommand cm = new SqlCommand("myQuery", cn)) { // 可能添加SQL参数 using (SqlDataReader reader = cm.ExecuteReader()) { // 从reader对象中读取值 return myReadValues; } } }
\n这样做是正确的方式吗?这种嵌套using
块的方式是否过度?我对这种嵌套using
块的层次有点不确定,但我当然希望按照正确的方式做。\n谢谢!
SqlConnection SqlCommand SqlDataReader IDisposable问题的出现原因是需要在某些情况下保持SqlDataReader打开,但同时也需要确保SqlConnection得到正确的释放。解决方法是使用CommandBehavior.CloseConnection参数来获取SqlDataReader对象,确保在SqlDataReader关闭或释放时,SqlConnection也会关闭和释放。
具体解决方法如下所示:
var cn = new SqlConnection("myConnectionstring"); var cm = new SqlCommand("myQuery", cn); var reader = cm.ExecuteReader(CommandBehavior.CloseConnection); return reader;
上述代码中,使用CommandBehavior.CloseConnection参数获取SqlDataReader对象。一旦SqlDataReader关闭或释放,SqlConnection也会关闭和释放。
为了确保SqlConnection和SqlDataReader正确释放,可以使用using语句来自动释放资源:
using(var reader = GetReader()) // 包含上述代码 { ... } // reader被释放,SqlConnection也被释放。
需要注意的是,上述代码中的GetReader方法示例存在问题,如果new SqlCommand或ExecuteReader抛出异常,将不会释放SqlConnection资源。为了实现更完整的实现,可以参考以下答案:
http://stackoverflow.com/a/744307/13087
总结起来,当需要保持SqlDataReader打开时,可以使用CommandBehavior.CloseConnection参数来确保在SqlDataReader关闭或释放时,SqlConnection也会关闭和释放。使用using语句可以简化资源释放的过程。
SqlConnection SqlCommand SqlDataReader IDisposable问题的出现原因是在使用嵌套的using块时,代码的自动缩进可能会导致SqlConnection对象没有正确打开连接。解决方法是手动打开连接,并在using块内执行其他必要的操作。
以下是解决方法的代码示例:
using (SqlConnection cn = new SqlConnection("myConnectionstring")) { cn.Open(); // 手动打开连接 using (SqlCommand cm = new SqlCommand("myQuery", cn)) { cm.Parameters.AddWithValue("param1", value1); // 添加参数 using (SqlDataReader reader = cm.ExecuteReader()) { // 从reader对象中读取值 return myReadValues; } } }
通过手动打开连接和在合适的位置执行其他必要的操作,可以确保代码在使用嵌套的using块时正常工作。这样做可以避免由于自动缩进而导致的连接未正确打开的问题。
这是百分之百正确的方法。如果一个类使用了IDisposable接口,应该将其包装在using语句中,以确保调用Dispose()方法。此外,与外部技术(尤其是SQL Server这样的非托管技术)进行通信是非常重要的。SqlCommand对象实现了IDisposable接口,这是有很好的原因的。下面的代码是SqlCommand对象的Dispose()方法:
protected override void Dispose(bool disposing)
{
if (disposing)
{
this._cachedMetaData = null;
}
base.Dispose(disposing);
}
从代码中可以看到,它释放对_cachedMetaData对象的引用,以便它也可以得到清理。
非常感谢你的答案,特别是关于SqlCommand的dispose的详细信息 - 这正是我在寻找的信息!
_100,我很高兴能够提供帮助!
只是提醒一下,“using”是一个语法糖,用于try --> finally块,在finally中调用Dispose。但不要这样做 - 使用using关键字。
“它释放对_cachedMetaData对象的引用” - 但在OP的例子中,_cachedMetaData对象在其所在的SqlCommand超出范围时就变得可回收了,而不使用using语句的情况下,它可能比使用它更早。注意,我并不是在反对调用Dispose:最好不要依赖对SqlCommand内部的了解,只是盲目地遵循这个模式。