Entity Framework(VB.NET)中SaveChanges报错后如何继续执行INSERT
解决EF6中日期主键冲突导致SaveChanges()中断、无法继续插入的问题
我之前处理过类似的EF批量插入场景,你碰到的核心问题其实是EF默认的事务特性和异常捕获范围不对:
首先,EF的SaveChanges()默认是原子事务操作——所有你添加到上下文的实体都会在同一个事务里提交,只要有一条触发主键冲突(或者其他数据库级错误),整个事务就会回滚;而且你原代码里的OptimisticConcurrencyException是用来处理并发更新冲突的,根本不是主键重复的错误类型,自然抓不住异常。
下面是具体的解决思路和修改后的代码:
关键问题拆解
- 主键冲突属于SQL Server的
SqlException,对应错误码是2627(唯一约束/主键重复),你的原catch块没针对这个异常做处理,通用Exception可能因为调试时VS的异常中断设置,没走到处理逻辑。 - 批量提交的事务性导致一条失败全失败,必须改成逐条处理+跳过错误实体,或者分组批量处理,失败后拆分排查。
修改后的可运行代码
For Each cpt As dbo.XXX In compt Dim RSK As New dbo.YYY RSK.RSK_UNITE = cpt.RES_UNITE RSK.RSK_CODE = cpt.RES_CODE RSK.RSK_DATE = valeurs.Item3 ' 日期类型主键 ' 每条数据单独提交,避免一条失败连累全部 Try db.dbo.YYY.Add(RSK) Dim num As Integer = db.SaveChanges() Catch sqlEx As SqlException ' 精准匹配主键冲突错误 If sqlEx.Number = 2627 Then ' 把错误实体从上下文移除,防止影响后续提交 db.Entry(RSK).State = EntityState.Detached MsgBox($"跳过重复日期主键的数据:{valeurs.Item3}") Else MsgBox($"SQL异常:{sqlEx.ToString()}") End If Catch ex As Exception MsgBox($"其他未知错误:{ex.ToString()}") ' 无论什么错误,都要移除上下文里的问题实体 db.Entry(RSK).State = EntityState.Detached End Try Next
效率优化建议
如果你的数据量很大,逐条提交效率会偏低,可以改成分组批量处理:比如每50条一组,先添加到上下文,提交时如果失败,再把这组拆成单条逐个处理,这样既保证效率,又能容错。
另外,最好在添加前先做预检查,提前过滤掉重复主键的数据,比事后捕获异常更高效:
' 先检查数据库是否已存在该日期的记录 Dim hasDuplicate = db.dbo.YYY.Any(Function(item) item.RSK_DATE = valeurs.Item3) If Not hasDuplicate Then ' 执行实体添加和提交逻辑 End If
原代码为什么没捕获到异常?
你原代码里把所有实体都添加完才调用SaveChanges(),此时抛出的是SqlException,但如果你的通用Exception没触发,大概率是VS调试时的异常设置导致的——VS默认会在SQL异常抛出时直接中断程序,而不是走到catch块,你可以在VS的「调试」→「Windows」→「异常设置」里,找到「Common Language Runtime Exceptions」→「System.Data.SqlClient.SqlException」,取消勾选「抛出」时中断,这样代码就能正常走到catch块了。
内容的提问来源于stack exchange,提问作者Esteban Lueger
相关产品推荐
相关产品推荐

