是否有任何可能的方法来执行此操作而不会出现此错误“已经有一个与此Connection关联的打开的DataReader必须先关闭。”我已经尝试使用“dr.close()
”,我收到另一个错误,上面写着“读取器关闭时无效的读取尝试”。你能救我吗?
继承我的代码:
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
Label2.Text = AllPicker1.Text
Label3.Text = AllPicker2.Text
If AllPicker1.Value >= AllPicker2.Value Then
MsgBox("End Date Must be Greater!")
Else
Dim SQLstatement As String = "SELECT * FROM tblStudInfo,tbl_studentLog WHERE tblStudInfo.StudID = tbl_studentLog.StudentNumber AND tbl_studentLog.LoginDate BETWEEN '" & AllPicker1.Text & "' AND '" & AllPicker2.Text & "'"
OpenData(SQLstatement)
End If
End Sub
Public Sub OpenData(ByRef SQLstatement As String)
Dim cmd As MySqlCommand = New MySqlCommand
With cmd
.CommandText = SQLstatement
.CommandType = CommandType.Text
.Connection = SqlConnection
dr = .ExecuteReader()
End With
While dr.Read
Dim SQLstatementSave As String = "INSERT INTO tbl_report (RepStudNo,RepName,RepCourse,RepDept,RepLogTime,RepLogdate) VALUES ('" & dr("StudID") & "','" & dr("Name") & "','" & dr("Course") & "','" & dr("Dept") & "','" & dr("LoginTime") & "','" & dr("LoginDate") & "') "
dr.Close()
Save(SQLstatementSave)
End While
SqlConnection.Close()
SqlConnection.Dispose()
SqlConnection.Open()
End Sub
Public Sub Save(ByRef SQLstatementSave As String)
Dim cmd As MySqlCommand = New MySqlCommand
With cmd
.CommandText = SQLstatementSave
.CommandType = CommandType.Text
.Connection = SqlConnection
.ExecuteNonQuery()
End With
SqlConnection.Close()
SqlConnection.Dispose()
SqlConnection.Open()
End Sub
End Class
答案 0 :(得分:3)
您似乎只使用一个SqlConnection。对于大多数数据库系统,在读取连接时无法重用连接。您可以将所有数据读入内存/ DataTable并在此之后处理行,或者为插入使用不同的SqlConnection。
使用SqlConnections,读者和命令时,我发现Using Statement非常有助于可视化对象的使用和创建。
答案 1 :(得分:0)
我们可以将其减少为单个查询:
INSERT INTO tbl_report
(RepStudNo,RepName,RepCourse,RepDept,RepLogTime,RepLogdate)
SELECT StudID, Name, Course, Dept, LoginTime, LoginDate
FROM tblStudInfo
INNER JOIN tbl_studentLog ON tblStudInfo.StudID = tbl_studentLog.StudentNumber
WHERE tbl_studentLog.LoginDate BETWEEN @StartDate AND @EndDate
请注意使用完整的INNER JOIN语法。应避免使用旧的TableA,TableB连接语法。另请注意您的日期使用占位符。 这很重要。
现在我需要引起注意我看到的几个函数:OpenData()和Save()。
这两个函数从根本上被打破,因为它们会强迫您以一种让您容易受到sql注入黑客攻击的方式构建查询。有一天,有人会将这样的值放入查询中包含的文本框中:
'; DROP表tbl_studentLog; -
仔细考虑如果有人在您的AllPicker1.Text
中输入了该内容会发生什么。这对日期选择器来说很难做到,但我敢打赌你有其他纯文本字段可以允许这样做。我提议的输入中的第一个字符(单引号)将关闭查询中的字符串文字。第二个字符(分号)将结束单个语句,但sql server 将不会停止执行代码。下一组字符构成一个额外的声明,放弃您的表。最后两个字符注释掉后面的任何内容,以避免由于语法错误而导致sql server拒绝或未提交命令。是的,Sql Server 将运行该附加语句,如果这是您放入文本框中的内容。
因此,您编写的方法已被破坏,因为只接受完成的sql字符串作为输入。调用数据库的任何函数必须还包括一个接受查询参数的机制。您最终希望运行更像这样的代码:
Public Sub CreateReport(ByVal StartDate As DateTime, ByVal EndDate As DateTime)
Dim sql As String = _
"INSERT INTO tbl_report " & _
" (RepStudNo,RepName,RepCourse,RepDept,RepLogTime,RepLogdate) " & _
" SELECT StudID, Name, Course, Dept, LoginTime, LoginDate " & _
" FROM tblStudInfo " & _
" INNER JOIN tbl_studentLog ON tblStudInfo.StudID = tbl_studentLog.StudentNumber " & _
" WHERE tbl_studentLog.LoginDate BETWEEN @StartDate AND @EndDate"
'.Net is designed such in most cases that you really do want a new SqlConnection for each query
'I know it's counter-intuitive, but it is the right way to do this
Using cn As New SqlConnection("Connection string"), _
cmd As New SqlCommand(sql, cn)
'Putting your data into the query using parameters like this is safe from injection attacks
cmd.Parameters.Add("@StartDate", SqlDbType.DateTime).Value = StartDate
cmd.Parameters.Add("@EndDate", SqlDbType.DateTime).Value = EndDate
cn.Open()
cmd.ExecuteNonQuery()
End Using
End Sub
有一点需要指出的是,乍一看我并没有关闭连接。但是,Using
块将确保连接立即关闭... 即使抛出异常。如果出现异常,您现有的代码将挂起连接。
另请注意,在阅读器打开时需要执行单独查询的整个问题这个整齐的侧面步骤...但是如果你真的需要这样做(它是罕见的)答案很简单:使用单独的连接。
答案 2 :(得分:0)
而不是:
Dim SQLstatementSave As String = "INSERT INTO tbl_report
(RepStudNo,RepName,RepCourse,RepDept,RepLogTime,RepLogdate)
VALUES ('" & dr("StudID") & "','" & etc.
尝试在DR()引用上使用.ToString。
Dim SQLstatementSave As String = "INSERT INTO tbl_report
(RepStudNo,RepName,RepCourse,RepDept,RepLogTime,RepLogdate)
VALUES ('" & dr("StudID").ToString & "','" & etc.