2013-10-04 40 views
0

是否有任何可能的方式来执行此操作而不会出现此错误“已经有一个与此连接关联的打开的DataReader,必须先关闭该连接。”我已经尝试使用“dr.close()”,并且我收到另一个错误,指出“读取器关闭时读取无效尝试”。你能帮我吗?如何在打开阅读器的情况下在VB中打开execuete查询?

继承人我的代码:

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 
+1

像这样构建查询的字符串连接会让您容易受到sql注入攻击。这真是太糟了。** –

回答

3

看来你只使用一个SqlConnection的。对于大多数数据库系统,在读取数据库时不能重新使用连接。您可以将所有数据读取到内存/ DataTable中,然后处理其中的行或对插入使用不同的SqlConnection。

使用SqlConnections,读者和命令时,我发现Using Statement非常有助于可视化对象的使用和创建。

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 TABLE 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块将确保即时关闭连接...即使发生异常,也可以使用。您的现有代码会在连接异常的情况下挂起连接。

另外请注意,这个整齐的侧步需要,而你的读者打开来执行一个单独的查询的整个问题...但如果你做的真的需要做到这一点(这是罕见),答案是简单:使用单独的连接

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. 
相关问题