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:违反主键的主要内容,如果未能解决你的问题,请参考以下文章