0

请看下面的代码:

Private objCommand As SQLCommand 

Public Overrides Function ExecuteDataReader(ByVal strCommandType As String, ByVal sqlCommandString As String) As DbDataReader
    Dim objDR As SqlDataReader

    Try
        _objCon = getConnection()
        _objCon.Open()
        Using _objCon
            Using _objCommand
                _objCommand.Connection = _objCon
                _objCommand.CommandText = sqlCommandString
                _objCommand.CommandType = strCommandType
                objDR = _objCommand.ExecuteReader
                ExecuteDataReader = objDR
            End Using
        End Using
    Catch ex As Exception
        Throw
    Finally
        _objCon = Nothing
        _objCommand.Dispose()
        _objCommand = Nothing
        objDR = Nothing
    End Try
End Function

返回关闭,DataReader因为它在连接对象关闭时关闭。连接对象的寿命如何DataReader

我一直在寻找类似的问题,我发现了这个问题:DataReader not closed when Connection is closed,后果?. 但是,它没有回答我的具体问题。

4

2 回答 2

2

您的连接过早关闭的原因是您在退出Using块之前不会从函数返回。离开 Using 块的行为将强制您的连接立即关闭。将 datareader 设置为返回的对象是不够的。即使使用显式的 Return 语句也不够……离开函数仍然意味着离开 Using 块,因此在您使用数据读取器之前,您的连接仍然关闭。


为了解决所有这些问题,我使用了如下所示的模式:

Public Iterator Function ExecuteDataReader(Of T)(ByVal sql As String, ByVal addParams as Action(Of SqlParameterCollection), ByVal castRow As Funnction(Of IDataRecord, T)) As IEnumerable(Of T)

    Using cn As SqlConnection = getConnection(), _
          cmd As New SqlCommand(sql, cn)

        addParams(cmd.Parameters)
        cn.Open()

        Using rdr As SqlDataReader = cmd.ExecuteReader()
            While rdr.Read()
                Yield castRow(rdr)
            End While
        End Using
    End Using
End Function

然后我会这样调用该函数:

Dim results As IEnumerable(Of Customer) = ExecuteDataReader( _
           "SELECT * FROM Customer WHERE Sales> @MinSales", _
      Sub(p) p.Add("@MinSales", SqlDbType.Double).Value = 10000.0, _
      Function(r) New Customer() With {Name=r("Name"), Address=r("Address"), Sales=r("Sales") })

For Each c As Customer in results
   '...
Next

让我们稍微回顾一下这个模式,因为有些事情会让人困惑……即我想涵盖委托参数。

首先是 addParameter 参数。您需要了解的是,您的原始模式被严重破坏了,因为它迫使您创建充斥着 Sql 注入漏洞的代码,因为没有其他方法可以发送参数信息。这是一个巨大的问题。幸运的是,它很容易解决。这就是 addParameter 参数的用途。这不是唯一的方法——也就是说,你也可以做一些简单的事情,比如传递一个键/值/类型的数组——但我喜欢它,因为它避免了通过数组的重复工作或存储参数数据的重复内存两次。

接下来是 castRow 参数。这是必要的,因为没有它,您会遇到与示例类似的问题。在这里,代码仍然会运行,但是因为您在其他地方不断产生相同的目标代码,最终将全部使用结果中的最终记录。这样,您可以获得正确的预期结果,并且以强类型的方式获得它们。

继续前进,希望您已经熟悉 Iterator 和 Yield 关键字,但由于它们对 VB.Net 来说相对较新,如果您不熟悉也没关系。只要知道它们会导致编译器将此代码转换为可以迭代您的数据读取器对象的东西。

于 2012-11-16T18:03:41.870 回答
0

您可以使用 ExecuteReader 的过载并传递 CommandBehaviour.Close,然后当阅读器处理完其余部分时,它会变得混乱,并且您会失去对生命周期的控制。

我的建议是不要这样做,我在一个项目中做过,虽然我仍然喜欢 DataReader 作为一种轻量级访问,并且不喜欢 Datatable,但我不再传递 raeders,错误的范围太大。这是代码、连接池和垃圾收集器之间的持续斗争,你不会赢。

使用 DataTable、EF、Linq 或只是老式的 IEnumberable

于 2012-11-16T18:04:50.713 回答