请查看以下代码:
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, consequences?。但是,它没有回答我的具体问题。
答案 0 :(得分:2)
您的连接过早关闭的原因是您在退出Using
块之前不会从函数返回。离开使用块的行为将强制您的连接立即关闭。将datareader设置为返回的对象是不够的。即使使用显式的Return语句也是不够的......离开函数仍然意味着离开Using块,所以在你开始使用datareader之前你的连接仍然关闭。
为了解决这些问题,我使用了这样的模式:
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来说比较新,所以如果你不是。只要知道它们会导致编译器将此代码转换为可以迭代datareader对象的内容。
答案 1 :(得分:0)
你可以使用ExecuteReader的重载并传递CommandBehaviour.Close,然后当读者被处理掉其余部分时,它会变得混乱,你就会失去对生命周期的控制。
我的推荐是不要这样做,我在一个项目中做了,虽然我仍然喜欢DataReader作为轻量级访问,并且不喜欢Datatable,我不再传递raeders,错误的范围太大。这是代码,连接池和Garbarge收集器之间的持续争斗,你将赢得胜利。
使用DataTable,EF,Linq或只是一个老式的IEnumberable