VB.NET一键执行多条Insert查询的问题及解决方法求助
问题分析与解决方案
核心问题
- OleDbCommand参数未清空:重复使用同一个
cmd对象执行不同SQL时,之前添加的参数会保留在集合中,导致后续SQL执行时参数数量/名称不匹配,出现"参数无默认值"或数据串入其他表的问题。 - 重复定义
saveorder方法:代码中存在两个完全相同的saveorder方法,会引发编译逻辑错误。 - invoice_id获取方式错误:插入
invoice后未获取数据库自动生成的主键ID,直接使用输入框值可能为空或无效,导致invoice_items插入失败。 - 连接管理不规范:频繁关闭/打开数据库连接,且未使用
Using语句自动释放资源,容易引发连接泄漏。
修复步骤
- 为每个SQL操作创建新的
OleDbCommand对象(或每次执行前清空参数集合),避免参数累积。 - 删除重复的
saveorder方法,保留一个实现。 - 插入
invoice后,使用SELECT SCOPE_IDENTITY()获取自动生成的invoice_id,用于后续invoice_items插入。 - 使用
Using语句管理OleDbConnection和OleDbCommand,确保资源自动释放,无需手动频繁开关连接。
修复后的代码示例
Private Sub add_Click(sender As Object, e As EventArgs) Handles add.Click If String.IsNullOrEmpty(client_name.Text) Or String.IsNullOrEmpty(company_name.Text) Or String.IsNullOrEmpty(email.Text) Or String.IsNullOrEmpty(contact_no.Text) Or String.IsNullOrEmpty(address.Text) Or String.IsNullOrEmpty(delivery_address.Text) Then MessageBox.Show("请填写所有字段", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error) Else If issaved = 1 Then MessageBox.Show("费用已保存", "保存提示", MessageBoxButtons.OK, MessageBoxIcon.Information) Else saveorder() issaved = 1 End If End If End Sub Public Sub saveorder() Dim debit As Int64 = Convert.ToInt64(total_basic_amount.Text) + Convert.ToInt64(freigh_rate.Text) + Convert.ToInt64(delivery_rate.Text) Dim invoiceId As Integer = 0 ' 使用Using管理连接,自动释放资源 Using cn As New OleDbConnection("你的数据库连接字符串") cn.Open() ' 插入ledger借方记录 Using cmd As New OleDbCommand("insert into ledger([client_name],[registration_no],[company_name],[date],[credit],[debit])Values(@client_name,@registration_no,@company_name,@date,@credit,@debit)", cn) cmd.Parameters.AddWithValue("@client_name", client_name.Text) cmd.Parameters.AddWithValue("@registration_no", reg_no.Text) cmd.Parameters.AddWithValue("@company_name", company_name.Text) cmd.Parameters.AddWithValue("@date", datetime.Value.ToShortDateString) cmd.Parameters.AddWithValue("@credit", 0) cmd.Parameters.AddWithValue("@debit", debit) cmd.ExecuteNonQuery() End Using MessageBox.Show("ledger借方记录已存储") ' 插入ledger贷方记录 Using cmd As New OleDbCommand("insert into ledger([client_name],[registration_no],[company_name],[date],[credit],[debit])Values(@client_name,@registration_no,@company_name,@date,@credit,@debit)", cn) cmd.Parameters.AddWithValue("@client_name", client_name.Text) cmd.Parameters.AddWithValue("@registration_no", reg_no.Text) cmd.Parameters.AddWithValue("@company_name", company_name.Text) cmd.Parameters.AddWithValue("@date", datetime.Value.ToShortDateString) cmd.Parameters.AddWithValue("@credit", Convert.ToInt64(advance_received_amount.Text)) cmd.Parameters.AddWithValue("@debit", 0) cmd.ExecuteNonQuery() End Using MessageBox.Show("ledger贷方记录已存储") ' 插入invoice并获取自动生成的ID Using cmd As New OleDbCommand("insert into invoice([invoice_date],[client_name],[client_company_name],[client_email],[client_contact_no],[client_address],[client_delivery_address],[total_basic_amount],[freight_rate],[delivery_rate],[advanced_amount],[pending_amount]) values(@invoice_date,@client_name,@client_company_name,@client_email,@client_contact_no,@client_address,@client_delivery_address,@total_basic_amount,@freight_rate,@delivery_rate,@advanced_amount,@pending_amount); SELECT SCOPE_IDENTITY();", cn) cmd.Parameters.AddWithValue("@invoice_date", datetime.Value.ToShortDateString) cmd.Parameters.AddWithValue("@client_name", client_name.Text) cmd.Parameters.AddWithValue("@client_company_name", company_name.Text) cmd.Parameters.AddWithValue("@client_email", email.Text) cmd.Parameters.AddWithValue("@client_contact_no", contact_no.Text) cmd.Parameters.AddWithValue("@client_address", address.Text) cmd.Parameters.AddWithValue("@client_delivery_address", delivery_address.Text) cmd.Parameters.AddWithValue("@total_basic_amount", total_basic_amount.Text) cmd.Parameters.AddWithValue("@freight_rate", freigh_rate.Text) cmd.Parameters.AddWithValue("@delivery_rate", delivery_rate.Text) cmd.Parameters.AddWithValue("@advanced_amount", advance_received_amount.Text) cmd.Parameters.AddWithValue("@pending_amount", total_pending_amount.Text) ' 获取插入后的invoice_id invoiceId = Convert.ToInt32(cmd.ExecuteScalar()) End Using MessageBox.Show("invoice已存储") ' 插入invoice_items(排除DataGridView最后一行空行) For i As Integer = 0 To DataGridView1.Rows.Count - 2 Using cmd As New OleDbCommand("insert into invoice_items([invoice_id],[item_name],[qty],[rate])Values(@invoice_id,@item_name,@qty,@rate)", cn) cmd.Parameters.AddWithValue("@invoice_id", invoiceId) cmd.Parameters.AddWithValue("@item_name", DataGridView1.Rows(i).Cells(2).Value) cmd.Parameters.AddWithValue("@qty", DataGridView1.Rows(i).Cells(3).Value) cmd.Parameters.AddWithValue("@rate", DataGridView1.Rows(i).Cells(4).Value) cmd.ExecuteNonQuery() End Using Next MessageBox.Show("发票明细已存储") End Using End Sub
额外优化建议
- 不要直接用
Convert.ToInt64转换文本框内容,添加输入验证(比如用Int64.TryParse),避免输入非数字时抛出异常。 - 数据库表字段类型要和代码中传入的参数类型匹配(比如日期字段直接传入
DateTime类型,而非转换为字符串)。 - 所有数据库操作建议包裹在
Try-Catch块中,捕获并处理异常,避免程序崩溃。
内容的提问来源于stack exchange,提问作者John MacClain
相关产品推荐
相关产品推荐

