【问题标题】:ConnectionString property. The connection's current state连接字符串属性。连接的当前状态
【发布时间】:2016-03-02 03:02:39
【问题描述】:

这是我的登录表单的当前编码

 Option Strict On
'-------------------------------------------
' Imports required for DB Connectivity
'------------------------------------------
Imports System.Data.OleDb
Imports ShadowLogin.GlobalVariables

Public Class ShadowLogin
Dim Main As New ShadowMain

'-------------------------------------------------------------------------------------------------------------------------------
' Establish Database Connectivity parameters
'-------------------------------------------------------------------------------------------------------------------------------
Dim cnnOLEDB As New OleDbConnection
Dim cmdOLEDB As New OleDbCommand
Dim strConnectionString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Environment.CurrentDirectory & "\shadow.mdb"


'-------------------------------------------------------------------------------------------
' System Login
'-------------------------------------------------------------------------------------------
Private Sub btnLogin_Click(sender As Object, e As EventArgs) Handles btnLogin.Click

    Dim selectedbutton As New RadioButton
    Dim Cancel As Boolean

    'Checks RedID is numerical digits only 
    If Not IsNumeric(txtRedID.Text) Then
        MsgBox("Please Check RedID.", vbInformation)

        'you may also consider erasing it
        txtRedID.Text = ""
        txtRedID.Focus()
        Exit Sub

        'checks that RedID is 9 characters long
    ElseIf txtRedID.Text.Length < 9 Then
        txtRedID.Focus()
        txtRedID.SelectAll()
        MsgBox("Please Check RedID", MsgBoxStyle.Exclamation)
        Exit Sub
    Else
        Cancel = True
    End If

    'Checks that a password has been entered
    If txtPassword.Text = "" Then
        MsgBox("Please Enter a Password", MsgBoxStyle.Exclamation, MsgBoxStyle.OkOnly)
        Exit Sub
    End If

    'if radiobutton is selected then continue
    If GroupBox1.SelectedRadioButton(selectedbutton) Then
        Main = New ShadowMain
        'Checks if radiobutton is selected and hides tabs 
        If optStudent.Checked = True Then
            ShadowMain.TabControl1.TabPages.Remove(ShadowMain.TabPage2)
            ShadowMain.TabControl1.TabPages.Remove(ShadowMain.TabPage3)

        ElseIf optFaculty.Checked = True Then
            ShadowMain.TabControl1.TabPages.Remove(ShadowMain.TabPage1)
            ShadowMain.TabControl1.TabPages.Remove(ShadowMain.TabPage3)

        ElseIf optDepartmentChair.Checked = True Then
            ShadowMain.TabControl1.TabPages.Remove(ShadowMain.TabPage1)
            ShadowMain.TabControl1.TabPages.Remove(ShadowMain.TabPage2)

        End If
    Else

        'if no radiobutton is selected display messagebox
        MsgBox("Please select a role")
        Exit Sub
    End If

    ' Check which role is selected and proceed accordingly


    '--------------------------------------------------------------------------------
    ' Student Role Login
    '--------------------------------------------------------------------------------
    If optStudent.Checked Then 'If user select a student role


        ' Let's Search for the User and Password

        cnnOLEDB.ConnectionString = strConnectionString
        cnnOLEDB.Open()
        ' Select the Student Record base on User Input
        cmdOLEDB.CommandText = "SELECT * FROM [Student] WHERE [SRedID]=" & txtRedID.Text
        cmdOLEDB.Connection = cnnOLEDB
        Dim rdrOLEDB As OleDbDataReader = cmdOLEDB.ExecuteReader

        'If we can find a match..
        If rdrOLEDB.Read = True Then
            ' See that the User, Password and Active status okay
            If rdrOLEDB.Item(0).ToString = txtRedID.Text And rdrOLEDB.Item(9).ToString = txtPassword.Text And rdrOLEDB.Item(13).ToString = "True" Then
                'Populate global userID (for future needs)
                userID = txtRedID.Text()
                'Populate a role for (for future needs)
                role = "Student"
                'Cleanup the login form
                Call LoginCleanup()
                ' Populate personal data in the Student Home
                ShadowMain.lblLName.Text = rdrOLEDB.Item(1).ToString
                ShadowMain.lblFName.Text = rdrOLEDB.Item(3).ToString
                ShadowMain.lblMIn.Text = rdrOLEDB.Item(2).ToString
                ShadowMain.lblAddOne.Text = rdrOLEDB.Item(5).ToString
                ShadowMain.lblCity.Text = rdrOLEDB.Item(6).ToString
                ShadowMain.lblState.Text = rdrOLEDB.Item(7).ToString
                ShadowMain.lblZip.Text = rdrOLEDB.Item(8).ToString
                ShadowMain.lblPhone.Text = rdrOLEDB.Item(10).ToString
                ShadowMain.lblEmail.Text = rdrOLEDB.Item(15).ToString
                'Show student home
                ShadowMain.Show()
                ' Close table and database connection (required) 
                rdrOLEDB.Close()
                cnnOLEDB.Close()
            Else
                'If user / password don't match
                MsgBox("Sorry, username or password not found", MsgBoxStyle.OkOnly, "Invalid Login")
                ' clear login window
                Call ClearLogin()
                ' Close table and database connection (required)
                rdrOLEDB.Close()
                cnnOLEDB.Close()
            End If
        Else
            ' Close table and database connection (required)
            rdrOLEDB.Close()
            cnnOLEDB.Close()
            'If user / password don't match
            MsgBox("Sorry, username or password not found", MsgBoxStyle.OkOnly, "Invalid Login")
            Call ClearLogin()
        End If


        '--------------------------------------------------------------------------------
        ' Faculty Role Login
        '--------------------------------------------------------------------------------

    ElseIf optFaculty.Checked Then

        ' Let's Search for the User and Password
        cnnOLEDB.Close()
        cnnOLEDB.ConnectionString = strConnectionString
        cnnOLEDB.Open()
        cmdOLEDB.CommandText = "SELECT * FROM [Faculty] WHERE [FRedID]=" & txtRedID.Text
        cmdOLEDB.Connection = cnnOLEDB
        Dim rdrOLEDB As OleDbDataReader = cmdOLEDB.ExecuteReader


        'If we can find a match.
        If rdrOLEDB.Read = True Then
            If rdrOLEDB.Item(0).ToString = txtRedID.Text And rdrOLEDB.Item(5).ToString = txtPassword.Text And rdrOLEDB.Item(9).ToString = "True" Then
                userID = txtRedID.Text()
                role = "Faculty"
                Call LoginCleanup()
                ShadowMain.lblLastNameFac.Text = rdrOLEDB.Item(2).ToString
                ShadowMain.lblFirstNameFac.Text = rdrOLEDB.Item(3).ToString
                ShadowMain.lblMiddleIntFac.Text = rdrOLEDB.Item(4).ToString
                ShadowMain.lblOfficeFac.Text = rdrOLEDB.Item(8).ToString
                ShadowMain.lblPhoneFac.Text = rdrOLEDB.Item(6).ToString
                ShadowMain.lblEmailFacl.Text = rdrOLEDB.Item(7).ToString
                ShadowMain.Show()
                rdrOLEDB.Close()
                cnnOLEDB.Close()
            Else
                MsgBox("Sorry, username or password not found", MsgBoxStyle.OkOnly, "Invalid Login")
                Call ClearLogin()
                rdrOLEDB.Close()
                cnnOLEDB.Close()
            End If
        Else
            rdrOLEDB.Close()
            MsgBox("Sorry, username or password not found", MsgBoxStyle.OkOnly, "Invalid Login")
            Call ClearLogin()
        End If



        '--------------------------------------------------------------------------------
        ' Department Chair Role Login
        '--------------------------------------------------------------------------------

    ElseIf optDepartmentChair.Checked Then
        ' Let's Search for the User and Password
        Dim rdrOLEDB As OleDbDataReader = cmdOLEDB.ExecuteReader
        cnnOLEDB.Close()
        cnnOLEDB.ConnectionString = strConnectionString
        cnnOLEDB.Open()
        cmdOLEDB.CommandText = "SELECT [DCRedID,Password] FROM [DepartmentChair] WHERE [DCRedID]=" & txtRedID.Text
        cmdOLEDB.Connection = cnnOLEDB


        'If we can find a match..
        If rdrOLEDB.Read = True Then
            If rdrOLEDB.Item(0).ToString = txtRedID.Text And rdrOLEDB.Item(1).ToString = txtPassword.Text Then
                userID = txtRedID.Text()
                role = "Department Chair"
                Call LoginCleanup()
                ShadowMain.Show()
                rdrOLEDB.Close()
                cnnOLEDB.Close()
            Else
                MsgBox("Sorry, username or password not found", MsgBoxStyle.OkOnly, "Invalid Login")
                Call ClearLogin()
                rdrOLEDB.Close()
                cnnOLEDB.Close()
            End If
        Else
            rdrOLEDB.Close()
            cnnOLEDB.Close()
            MsgBox("Sorry, username or password not found", MsgBoxStyle.OkOnly, "Invalid Login")
            Call ClearLogin()
        End If
    End If


End Sub

我现在遇到的问题是,如果我第一次登录失败,然后再次尝试登录,我得到了错误:

不允许更改“ConnectionString”属性。连接的当前状态为打开。

我查找并找到了一个解决方案,说我需要确保我的连接事先关闭,它解决了这个问题,但现在我遇到了这个问题:

阅读器关闭时调用 Read 的尝试无效。

我尝试尽可能地标记所有内容,并在我的大部分代码中添加,因为人们总是要求查看它。 对此的任何帮助表示赞赏。

【问题讨论】:

  • 不要使用全局连接。创建它,使用它并为每次使用处理它。请参阅this answer OleDbCommand 对象几乎相同。
  • ...您还应该使用 SQL 参数来避免注入,并且密码不应该以明文形式存储,而应该被散列。
  • 谢谢,我查了一下散列密码,以前从没听说过。我也会看看那个帖子
  • Is it safe for me to store usernames and passwords in the database? 答案之一是在VB中拥有密码的完整代码
  • 那太棒了,我想看看使用它。感谢帮助

标签: vb.net ms-access connection-string oledb


【解决方案1】:

我真的建议您将庞大的代码块拆分成更小的部分。实际上,这段代码很难阅读和调试。为了控制连接的状态,您不得不引入对 Connection.Close 和 DataReader.Close 的虚假调用,但是,正如您所见,这很容易出错,因为您无法确定覆盖了所有代码路径。

相反,如果您引入更小的代码块,您可以更好地控制何时打开和关闭与相关阅读器的连接。

例如

If optStudent.Checked Then 'If user select a student role
    '--------------------------------------------------------------------------------
    ' Student Role Login
    '--------------------------------------------------------------------------------
   HandleStudentRole()
ElseIf optFaculty.Checked Then
    '--------------------------------------------------------------------------------
    ' Faculty Role Login
    '--------------------------------------------------------------------------------
     HandleFacultyRole()

ElseIf optDepartmentChair.Checked Then
    '--------------------------------------------------------------------------------
    ' Department Chair Role Login
    '--------------------------------------------------------------------------------
    HandleDepartmentRole()
End If

现在您可以编写较小的代码块,确保每个块都打开和关闭连接和阅读器(这里我将展示学生角色的块,但其他类似)

Private Sub HandleStudenRole()
  ' Let's Search for the User and Password

    Using cnnOLEDB = new OleDbConnection(strConnectionString)
    Using cmdOleDB = new OleDbCommand("SELECT * FROM [Student] WHERE [SRedID]= @studentID", cnnOleDB)
       cnnOLEDB.Open()
       ' Select the Student Record base on User Input
       cmdOleDb.Parameters.Add("@studentID", OleDbType.VarWChar).Value = Convert.ToInt32(txtRedID.Text)
       Using rdrOLEDB = cmdOLEDB.ExecuteReader
           'If we can find a match..
          If rdrOLEDB.Read = True Then
             ......
          Else
            'If user / password don't match
            MsgBox(....)
            ' clear login window
            Call ClearLogin()
          End If
       End Using
    End Using
    End Using
End Sub

我使用了Using statement,它允许删除您为关闭连接和阅读器而编写的所有代码。 Using 将确保在代码流从 using 块退出时调用 Close 和 Dispose 方法,如果您遇到异常也是如此。当然查询是参数化的(尽管在这种情况下很难利用 Sql Injection)

还要注意,在我的 HandleStudentRole 块中,变量 cnnOLEDBcmdOLEDB 是局部变量。您不再需要在全局范围内声明它们。如果您每次需要它们时对它们进行 declere 和初始化,性能不会下降,并且代码的简洁性要好得多。

【讨论】:

  • “如果您每次需要它们时 declere 和初始化 [连接],性能不会下降” - 与基于服务器的数据库相比,Access 不太确定。请记住,Access 是基于文件的 DBMS,因此它必须与数据库文件更加“亲密”,当数据库文件位于网络共享上时,这可能会有所不同。示例:VB.NET 测试应用程序在具有 2000 个表的 25MB .mdb 上执行 2 次选择。为两个 SELECT 保持连接打开会产生 429KB 的总网络流量。关闭和重新打开 SELECT 之间的连接将流量增加到 711KB(增加 66%)。
  • 嗯,可能是的,在这种情况下,你是对的。尽管如此,我觉得牺牲一些表现来避免家务麻烦(更不用说保持正确的习惯以更标准的方式工作)是值得考虑的事情。无论如何,这里的真正答案是 measure
  • @JamesSwan 这个答案提供了很多很好的建议来解决问题使您的代码更具可读性和组织性。如果有帮助,您应该单击它旁边的复选标记。稍后当您达到 15 岁时,您可以对您认为有帮助或有启发性的问题和答案(任何地方/任何地方)进行投票
  • 大约 10 分钟前才意识到那个复选标记是什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-22
相关资源
最近更新 更多