System.Data.SqlClient.SqlException:违反主键

Posted

技术标签:

【中文标题】System.Data.SqlClient.SqlException:违反主键【英文标题】:System.Data.SqlClient.SqlException: Violation of PRIMARY KEY 【发布时间】:2019-07-27 15:43:19 【问题描述】:

我创建了一个 SQL Server 数据库,我想在该数据库的特定表中添加一些数据。我使用一些文本框来输入数据并使用添加按钮来完成。但是当我点击按钮时,整个过程都停止了,并指示 DBSQL 模块中出现错误,如下所示。

这是我的代码:

Imports System.Data
Imports System.Data.SqlClient

Module DBSQLServer
    Public con As New SqlConnection("Data Source=JOYALXDESKTOP\SQLEXPRESS;Initial Catalog=SaleInventory;Integrated Security=True")
    Public cmd As New SqlCommand
    Public da As New SqlDataAdapter
    Public ds As New DataSet
    Public dt As DataTable
    Public qr As String
    Public i As Integer

    Public Function searchdata(ByVal qr As String) As DataSet
        da = New SqlDataAdapter(qr, con)
        ds = New DataSet
        da.Fill(ds)
        Return ds

    End Function

    Public Function insertdata(ByVal qr As String) As Integer

        cmd = New SqlCommand(qr, con)
        con.Open()
        i = cmd.ExecuteNonQuery()
        con.Close()
        Return i

    End Function
End Module

错误发生在这一行:

i = cmd.ExecuteNonQuery()

在表格中,我有 5 列:

ProID, ProName, ProDesc, ProPrice, ProStock

ProID 是我的主键。

这是我将数据添加到数据库中的添加按钮代码:

Private Sub Add_Click(sender As Object, e As EventArgs) Handles add.Click
        If (isformvalid()) Then
            qr = "Insert into tblProductInfo (ProName, ProDesc, ProPrice, ProStock) Values('" & nametext.Text & "','" & descriptiontext.Text & "','" & pricetext.Text & "','" & stocktext.Text & "')"
            Dim logincorrect As Boolean = Convert.ToBoolean(insertdata(qr))
            If (logincorrect) Then
                MsgBox("Stock Added Successfully ...", MsgBoxStyle.Information)
            Else
                MsgBox("Something Wrong. Record Not Saved. Please Check and Try Again...", MsgBoxStyle.Critical)
            End If
        End If
    End Sub

当我的查询是:

qr = "Insert into tblProductInfo (ProName, ProDesc, ProPrice, ProStock) Values('" & nametext.Text & "','" & descriptiontext.Text & "','" & pricetext.Text & "','" & stocktext.Text & "')"

错误如下:

System.Data.SqlClient.SqlException: '不能将 NULL 值插入到列 'ProID' 表 'SaleInventory.dbo.tblProductInfo' 中;列不允许空值。插入失败。

当我的查询是:

qr = "Insert into tblProductInfo (ProID, ProName, ProDesc, ProPrice, ProStock) Values('" & idtext.Text & "','" & nametext.Text & "','" & descriptiontext.Text & "','" & pricetext.Text & "','" & stocktext.Text & "')"  `

那么错误是:

System.Data.SqlClient.SqlException:'违反主键约束'PK_tblProductInfo'。无法在对象“dbo.tblProductInfo”中插入重复键。重复键值为 (1)。

【问题讨论】:

您是否忘记将 ProID 列设为自增列? 我不确定。我该如何检查?我目前使用的是 Microsoft SQL Server Management Studio。 SQL Injection alert - 您应该将您的 SQL 语句连接在一起 - 使用 参数化查询 来避免 SQL 注入 - 查看 Little Bobby Tables 如何检查? 在 SSMS 中右键单击您的表,选择 Design,选择主键行,查看 Column Properties 窗口并验证 Identity Specification 是否包含 Yes 表示 (Is Identity)、1 表示 Identity Seed 和 1 表示 身份增量 很高兴能提供帮助,但您应该真正注意@marc_s 评论。永远不要以这种方式编写查询。如果您将十进制值存储在字符串列中,我预计现在价格列会出现问题,反之亦然,如果您在需要十进制值时传递字符串值。了解如何使用参数 【参考方案1】:

这是因为在 tblProductInfo 中有一行 ProID=1。您应该编写代码以避免这种重复,例如,您可以首先运行脚本以在表中查找 ProID 的最大值(“从 tblProductInfo 中选择 MAX(ProID)”),然后使用 MAX(ProID)+1 运行查询。

【讨论】:

虽然这在大多数情况下应该有效。实际上最好依靠 IDENTITY 列而不处理自己的 ids。如果自己处理 Id,那么在大多数情况下,GUID 将是更合适的选择【参考方案2】:

假设您已更正数据库,使 ProdID 成为身份字段。

请注意,与用户界面的所有交互都是在表单代码中执行的。与数据库的所有交互都在模块中执行。尽管您仍然需要导入 System.Data(对于 DataTable 类型),但不必在 Form 中导入 System.Data.SqlClient。所有验证都在表单中完成。

在模块代码中,Using...EndUsing 块确保您的数据库对象即使出现错误也已关闭和处置。我已经演示了如何使用参数来避免 Sql 注入,但我不得不猜测数据类型。检查数据库的实际数据类型,并相应地调整 SqlDbType 和参数类型以及表单中的验证代码。

人脉是宝贵的资源。请注意,连接在最后一分钟打开,并在被 End Using 使用后立即关闭和处理。执行...

Module DBSQLServer
    Private conString As String = "Data Source=JOYALXDESKTOP\SQLEXPRESS;Initial Catalog=SaleInventory;Integrated Security=True"

    'Example of how your search function might look.
    Public Function searchdata(Name As String) As DataTable
        Dim dt As New DataTable
        Using cn As New SqlConnection()
            Using cmd As New SqlCommand("Select * From tblProductInfo Where Name = @Name", cn)
                cmd.Parameters.Add("@Name", SqlDbType.VarChar).Value = Name
                cn.Open()
                dt.Load(cmd.ExecuteReader)
            End Using
        End Using
        Return dt
    End Function

    Public Function insertdata(Name As String, Description As String, Price As Decimal, Stock As Integer) As Integer
        Dim i As Integer
        Using cn As New SqlConnection(conString)
            Using cmd As New SqlCommand("Insert into tblProductInfo (ProName, ProDesc, ProPrice, ProStock) Values(@Name,@Description, @Price, @Stock", cn)
                With cmd.Parameters
                    .Add("@Name", SqlDbType.VarChar).Value = Name
                    .Add("@Description", SqlDbType.VarChar).Value = Description
                    .Add("@Price", SqlDbType.Decimal).Value = Price
                    .Add("@Stock", SqlDbType.Int).Value = Stock
                End With
                cn.Open()
                i = cmd.ExecuteNonQuery
            End Using
        End Using
        Return i
    End Function
End Module

在形式上

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    'First check that  text boxes for string parameters are filled in
    If nametext.Text = "" OrElse descriptiontext.Text = "" Then
        MessageBox.Show("Please fill in all text boxes.")
        Return
    End If
    'Next check for valid numeric values
    Dim price As Decimal
    If Not Decimal.TryParse(pricetext.Text, price) Then
        MessageBox.Show("The price must be a number.")
        Return
    End If
    Dim stock As Integer
    If Not Integer.TryParse(stocktext.Text, stock) Then
        MessageBox.Show("Stock must be a whole number")
        Return
    End If
    Dim retVal As Integer = DBSQLServer.insertdata(nametext.Text, descriptiontext.Text, price, stock)
    If retVal = 1 Then
        MessageBox.Show("Product successfully added.")
    End If
End Sub

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    Dim dt = DBSQLServer.searchdata(txtSearch.Text)
    DataGridView1.DataSource = dt
End Sub

【讨论】:

以上是关于System.Data.SqlClient.SqlException:违反主键的主要内容,如果未能解决你的问题,请参考以下文章