2013-10-04 45 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. 
相關問題