C#中DataGridView更新SQL Server双表数据异常求助
解决PurchaseInvoiceDetails更新时新增条目无法保存的问题
兄弟,你的问题根源一眼就能看出来:你现在只在用UPDATE语句处理明细,但UPDATE只能修改数据库里已存在的记录。当你在DataGridView里新增一条订单明细时,这条记录在PurchaseInvoiceDetails表中根本不存在,UPDATE语句找不到匹配的行,自然不会把它保存进去。而当只有一条数据时,那条数据是原本就存在的,所以UPDATE能正常生效。
给你两个实用的解决方案,按需选择:
方案一:删除旧明细 + 重新插入所有当前明细(简单易实现)
这种方式适合订单明细数量不多的场景,逻辑简单不容易出错:
- 首先删除该订单下所有已有的明细记录(确保和DataGridView的数据完全同步)
DELETE FROM [dbo].[PurchaseInvoiceDetails] WHERE PurchaseInvoiceNo = @PurchaseInvoiceNo - 遍历DataGridView中的每一行,执行
INSERT语句把所有明细重新插入到表中INSERT INTO [dbo].[PurchaseInvoiceDetails] (PurchaseInvoiceNo, ProductCode, ProductName, Box, Quantity, Price, DiscountInPercent, DiscountAmount, Amount) VALUES (@PurchaseInvoiceNo, @ProductCode, @ProductName, @Box, @Quantity, @Price, @DiscountInPercent, @DiscountAmount, @Amount) - 关键提醒:把更新主表
PurchaseInvoice、删除旧明细、插入新明细的所有操作放在同一个数据库事务里,这样如果任何一步出错,所有操作都会回滚,避免出现主表更新了但明细表数据错乱的情况。
方案二:UPSERT(更新已有记录 + 插入新增记录)
如果需要保留原有明细记录(比如不想删除再插入),可以对每条明细判断是否存在,存在则更新,不存在则插入:
- 给
PurchaseInvoiceDetails加一个唯一标识(比如新增主键PurchaseInvoiceDetailID,或者用PurchaseInvoiceNo + ProductCode作为唯一约束,假设一个订单里同一个产品只能出现一次) - 对DataGridView的每一行:
- 如果该明细已存在(比如通过
PurchaseInvoiceNo和ProductCode能查到记录),执行你原来的UPDATE语句 - 如果不存在,执行
INSERT语句插入这条新明细
- 如果该明细已存在(比如通过
- 或者用SQL Server的
MERGE语句一次性处理,示例如下(需要把DataGridView的数据整理成临时表或表变量作为源数据):MERGE INTO [dbo].[PurchaseInvoiceDetails] AS Target USING @TempDetailsTable AS Source ON Target.PurchaseInvoiceNo = Source.PurchaseInvoiceNo AND Target.ProductCode = Source.ProductCode WHEN MATCHED THEN UPDATE SET Target.ProductName = Source.ProductName, Target.Box = Source.Box, Target.Quantity = Source.Quantity, Target.Price = Source.Price, Target.DiscountInPercent = Source.DiscountInPercent, Target.DiscountAmount = Source.DiscountAmount, Target.Amount = Source.Amount WHEN NOT MATCHED THEN INSERT (PurchaseInvoiceNo, ProductCode, ProductName, Box, Quantity, Price, DiscountInPercent, DiscountAmount, Amount) VALUES (Source.PurchaseInvoiceNo, Source.ProductCode, Source.ProductName, Source.Box, Source.Quantity, Source.Price, Source.DiscountInPercent, Source.DiscountAmount, Source.Amount);
额外注意事项
- 始终使用参数化查询(你已经在做了,这点很棒,继续保持,能有效防止SQL注入)
- 确保主表和明细表的操作在同一个事务中,保证数据一致性
- 如果你的业务允许,优先用方案一,逻辑简单,不容易出现遗漏或判断错误的情况
内容的提问来源于stack exchange,提问作者Farooq Ahmed
相关产品推荐
相关产品推荐

