如何在不影响上传照片到数据库的情况下正确执行rd.HasRow?

How to execute rd.HasRow properly without affecting uploading photo to database?

我正在尝试使用 rd.HasRow 方法在将输入的数据保存到数据库之前验证它是否重复。

如果是重复的,假设弹出错误信息框而不是保存数据。

我应该如何执行它以及我用来将照片上传到数据库的代码?如果我评论这部分代码,输入的数据(不重复)可以保存到数据库,但照片不会随之上传。

'i = cmd.ExecuteNonQuery()
'If i >= 1 Then
    'MessageBox.Show("Profile successfully registered!", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information)
'Else
    'MessageBox.Show("Error. Please try again later.", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information)
'End If

但如果我不这样做,用户输入的数据将不会被保存,并且会针对 i=cmd.ExecuteNonQuery():

弹出此错误消息

System.InvalidOperationException: 'There is already an open DataReader associated with this Command which must be closed first.'

这是整体代码。

Private Sub button2_Click(sender As Object, e As EventArgs) Handles button2.Click
    Dim con As New SqlConnection
    Dim cmd As New SqlCommand

    Dim rollno As String
    Dim name As String
    Dim gender As String
    Dim address As String
    Dim phoneno As Integer
    Dim datereg As String
    Dim faculty As String
    Dim course As String
    Dim semester As String
    Dim i As Integer
    Dim j As Integer

    rollno = TextBox1.Text
    name = TextBox2.Text
    gender = ComboBox4.Text
    address = TextBox3.Text
    phoneno = TextBox4.Text
    datereg = dateTimePicker1.Value
    faculty = comboBox1.Text
    course = comboBox2.Text
    semester = comboBox3.Text

    con.ConnectionString = "Data Source=LAPTOP-85ALBAVS\SQLEXPRESS;Initial Catalog=Portal;Integrated Security=True"
    cmd.Connection = con
    con.Open()

    'To validate whether duplication of typed in data by user occurs or not, if yes, error msg pop-up. If no, proceed and save the data into database
    Dim rd As SqlDataReader
    cmd.CommandText = "SELECT * FROM Profile WHERE RollNo= '" & TextBox1.Text & "' and Name='" & TextBox2.Text & "'"
    rd = cmd.ExecuteReader()
    If rd.HasRows Then
        MessageBox.Show("User already registered! Please try again.", "Error", MessageBoxButtons.OK)
    Else
        cmd.CommandText = "INSERT INTO Profile VALUES ('" & rollno & "' , '" & name & "' , '" & gender & "' , '" & address & "' , '" & phoneno & "' , '" & datereg & "' , '" & faculty & "' , '" & course & "' , '" & semester & "')"
    End If
    'i = cmd.ExecuteNonQuery()
    'If i >= 1 Then
    'MessageBox.Show("Profile successfully registered!", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information)
    'Else
    'MessageBox.Show("Error. Please try again later.", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information)
    'End If
    con.Close()

    con.Open()
    'To save the uploaded photo to table Photo

    Dim command As New SqlCommand("Insert into Photo (Img, Pid) Values (@Img, @Pid)", con)
    command.Connection = con
    Dim ms As New MemoryStream
    pictureBox1.Image.Save(ms, pictureBox1.Image.RawFormat)
    command.Parameters.Add("@Img", SqlDbType.Image).Value = ms.ToArray()
    command.Parameters.Add("@Pid", SqlDbType.VarChar).Value = TextBox1.Text

    j = cmd.ExecuteNonQuery()
    If j >= 1 Then
        MessageBox.Show("Profile successfully registered!", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information)
    Else
        MessageBox.Show("Error. Please try again later.", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information)
    End If
End Sub

在线评论和解释。

Private Sub OPCode()
        Dim i As Integer
        Dim j As Integer
        Dim rollno = TextBox1.Text
        Dim name = TextBox2.Text
        Dim gender = ComboBox4.Text
        Dim address = TextBox3.Text
        Dim phoneno = CInt(TextBox4.Text) 'Unless your phone numbers are very different
        'than the phone numbers here, the likelyhood of a user entering just numbers is
        'nil. Change this to a string and a VarChar in the database
        Dim datereg = dateTimePicker1.Value
        Dim faculty = comboBox1.Text
        Dim course = ComboBox2.Text
        Dim semester = ComboBox3.Text
        'The Using block ensures that your connection is closed and disposed
        'Pass your connection string to the constructor of the connection
        Using con As New SqlConnection("Data Source=LAPTOP-85ALBAVS\SQLEXPRESS;Initial Catalog=Portal;Integrated Security=True")
            'Pass the Sql command text and connection to the Constructor of the command.
            'NEVER, NEVER, NEVER allow user input to be passed directly to a database. Always use parameters.
            Dim cmd As New SqlCommand("SELECT * FROM Profile WHERE RollNo= @RollNo and [Name]= @Name;", con)
            cmd.Parameters.Add("@RollNo", SqlDbType.VarChar).Value = rollno
            cmd.Parameters.Add("@Name", SqlDbType.VarChar).Value = name
            con.Open()
            Using rd As SqlDataReader = cmd.ExecuteReader()
                'To validate whether duplication of typed in data by user occurs or not, if yes, error msg pop-up. If no, proceed and save the data into database
                If rd.HasRows Then
                    MessageBox.Show("User already registered! Please try again.", "Error", MessageBoxButtons.OK)
                    'You don't want to go any further if the user is registered.
                    Exit Sub
                End If
            End Using
            'Just use another new command variable to avoid confusion
            'I think it is much better practice to list the fields.
            Dim cmd2 As New SqlCommand("INSERT INTO Profile VALUES (@RollNo ,@Name,@Gender, @Address, @PhoneNo , @DateReg , @Faculty , @Course , @Semester);", con)
            cmd2.Parameters.Add() 'etc.
            i = cmd2.ExecuteNonQuery()
            If i >= 1 Then
                MessageBox.Show("Profile successfully registered!", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information)
            Else
                MessageBox.Show("Error. Please try again later.", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information)
                Exit Sub
            End If
            'To save the uploaded photo to table Photo
            Dim command3 As New SqlCommand("Insert into Photo (Img, Pid) Values (@Img, @Pid)", con)
            command3.Connection = con
            Dim ms As New MemoryStream
            pictureBox1.Image.Save(ms, pictureBox1.Image.RawFormat)
            command3.Parameters.Add("@Img", SqlDbType.Image).Value = ms.ToArray()
            command3.Parameters.Add("@Pid", SqlDbType.VarChar).Value = TextBox1.Text

            j = command3.ExecuteNonQuery()
        End Using
        If j >= 1 Then
                MessageBox.Show("Profile successfully registered!", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information)
            Else
                MessageBox.Show("Error. Please try again later.", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information)
            End If
    End Sub

代码看起来有点混乱,至少根据我的经验,调试混乱的代码可能很困难。我们可以做一些事情来纠正这个问题,我现在会尝试和你一起做。

首先,给你的控件起有意义的名字。您可以通过选择控件并更改 Name 属性 通过窗体上的设计来完成此操作。当通过代码引用它们时,这将极大地帮助您。在这种情况下,它还将帮助您消除对变量的需求。

考虑实施 Using:

Sometimes your code requires an unmanaged resource, such as a file handle, a COM wrapper, or a SQL connection. A Using block guarantees the disposal of one or more such resources when your code is finished with them. This makes them available for other code to use.

这将帮助您管理声明和资源,同时创建更清晰的代码图。

我还会考虑将每个命令分解成它自己的 Using 块,以使您的代码更清晰。

将数据插入数据库时​​考虑使用 SQL parameters to avoid SQL injection

最后是代码,让我们依次查看每个 Using 块。

首先,我将从在 Using 块中启动 SqlConnection 开始,然后我们可以为每个命令使用该连接:

Using con As New SqlConnection("Data Source=LAPTOP-85ALBAVS\SQLEXPRESS;Initial Catalog=Portal;Integrated Security=True")

    con.Open()

    'Add the rest of the code here

End Using

检查记录是否存在:

在这里,考虑声明一个 Boolean 变量,我们用它来确定记录是否存在。

Dim recordExists As Boolean = False
Using cmd As New SqlCommand("SELECT * FROM Profile WHERE RollNo = @RollNo AND Name = @Name", con)
    cmd.Parameters.Add("@RollNo", SqlDbType.[Type]).Value = txtRollNo.Text
    cmd.Parameters.Add("@Name", SqlDbType.[Type]).Value = txtName.Text

    Using reader As SqlDataReader = cmd.ExecuteReader()
        recordExists = reader.HasRows
    End Using
End Using

如果记录存在则显示提示,如果不存在则插入数据库:

If recordExists Then
    MessageBox.Show("User already registered! Please try again.", "Error", MessageBoxButtons.OK)
Else
    Using cmd As New SqlCommand("INSERT INTO Profile VALUES (@RollNo, @Name, @Gender, @Address, @PhoneNo, @DateReg, @Faculty, @Course, @Semester)", con)

        cmd.Parameters.Add("@RollNo", SqlDbType.[Type]).Value = txtRollNo.Text
        cmd.Parameters.Add("@Name", SqlDbType.[Type]).Value = txtName.Text
        cmd.Parameters.Add("@Gender", SqlDbType.[Type]).Value = cboGender.Text
        cmd.Parameters.Add("@Address", SqlDbType.[Type]).Value = txtAddress.Text
        cmd.Parameters.Add("@PhoneNo", SqlDbType.[Type]).Value = txtPhoneNo.Text
        cmd.Parameters.Add("@DateReg", SqlDbType.[Type]).Value = dtpDateReg.Value
        cmd.Parameters.Add("@Faculty", SqlDbType.[Type]).Value = cboFaculty.Text
        cmd.Parameters.Add("@Course", SqlDbType.[Type]).Value = cboCourse.Text
        cmd.Parameters.Add("@Semester", SqlDbType.[Type]).Value = cboSemster.Text

        If cmd.ExecuteNonQuery() > 0 Then
            MessageBox.Show("Profile successfully registered!", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information)
        Else
            MessageBox.Show("Error. Please try again later.", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information)
        End If
    End Using
End If

插入图片:

Using cmd As New SqlCommand("INSERT INTO Photo (Img, Pid) VALUES (@Img, @Pid)", con)

    Using ms As New MemoryStream()
        pbxImage.Image.Save(ms, pbxImage.Image.RawFormat)

        cmd.Parameters.Add("@Img", SqlDbType.Image).Value = ms.ToArray()
        cmd.Parameters.Add("@Pid", SqlDbType.VarChar).Value = txtName.Text
    End Using

    cmd.ExecuteNonQuery()
End Using

Note that I have used SqlDbType.[Type] where I am unsure of your data type within the database. You will want to replace this with the data type you have specified for each column.

你的代码看起来像这样:

Using con As New SqlConnection("Data Source=LAPTOP-85ALBAVS\SQLEXPRESS;Initial Catalog=Portal;Integrated Security=True")

    con.Open()

    Dim recordExists As Boolean = False
    Using cmd As New SqlCommand("SELECT * FROM Profile WHERE RollNo = @RollNo AND Name = @Name", con)
        cmd.Parameters.Add("@RollNo", SqlDbType.VarChar).Value = txtRollNo.Text
        cmd.Parameters.Add("@Name", SqlDbType.VarChar).Value = txtName.Text

        Using reader As SqlDataReader = cmd.ExecuteReader()
            recordExists = reader.HasRows
        End Using
    End Using

    If recordExists Then
        MessageBox.Show("User already registered! Please try again.", "Error", MessageBoxButtons.OK)
    Else
        Using cmd As New SqlCommand("INSERT INTO Profile VALUES (@RollNo, @Name, @Gender, @Address, @PhoneNo, @DateReg, @Faculty, @Course, @Semester)", con)

            cmd.Parameters.Add("@RollNo", SqlDbType.[Type]).Value = txtRollNo.Text
            cmd.Parameters.Add("@Name", SqlDbType.VarChar).Value = txtName.Text
            cmd.Parameters.Add("@Gender", SqlDbType.VarChar).Value = cboGender.Text
            cmd.Parameters.Add("@Address", SqlDbType.VarChar).Value = txtAddress.Text
            cmd.Parameters.Add("@PhoneNo", SqlDbType.VarChar).Value = txtPhoneNo.Text
            cmd.Parameters.Add("@DateReg", SqlDbType.VarChar).Value = dtpDateReg.Value
            cmd.Parameters.Add("@Faculty", SqlDbType.VarChar).Value = cboFaculty.Text
            cmd.Parameters.Add("@Course", SqlDbType.VarChar).Value = cboCourse.Text
            cmd.Parameters.Add("@Semester", SqlDbType.VarChar).Value = cboSemster.Text

            con.Open()

            If cmd.ExecuteNonQuery() > 0 Then
                MessageBox.Show("Profile successfully registered!", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information)
            Else
                MessageBox.Show("Error. Please try again later.", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information)
            End If
        End Using
    End If

    Using cmd As New SqlCommand("INSERT INTO Photo (Img, Pid) VALUES (@Img, @Pid)", con)

        Using ms As New MemoryStream()
            pbxImage.Image.Save(ms, pbxImage.Image.RawFormat)

            cmd.Parameters.Add("@Img", SqlDbType.Image).Value = ms.ToArray()
            cmd.Parameters.Add("@Pid", SqlDbType.VarChar).Value = txtName.Text
        End Using

        con.Open()

        cmd.ExecuteNonQuery()
    End Using

End Using

此代码未经测试,我没有环境,但它应该能为您提供一些有用的东西。