C#结合SQL Server使用LinqToSql插入时报DuplicateKeyException错误
DuplicateKeyException 异常排查方案
结合你提供的建表脚本、业务代码,可按以下概率从高到低定位问题:
- LINQ to SQL 自增主键映射配置错误(最高发诱因)
你的stagiaire表中id_stagiaire是设置了identity(1,1)的数据库自增主键,如果在DBML实体设计器中,没有将该字段的Auto Generated Value属性设置为True、同时将主键的Auto Sync设置为OnInsert,LINQ to SQL会默认该字段需要用户手动赋值。
此时新建stagiaire实体时,id_stagiaire作为int类型默认值为0。第一次插入时,因为生成的SQL会显式带上id_stagiaire=0,数据库会抛出identity列不能显式插入的错误;但因为上下文会持续追踪失败的实体,这个主键为0的实体不会被从缓存中移除。第二次点击按钮插入新实体时,新实体的主键同样是默认值0,上下文检测到缓存中已经存在同主键的追踪对象,就会直接抛出「无法添加键已存在的实体」的异常,此时根本不会走到数据库提交环节。 - 建表脚本的表存在性判断逻辑错误
你所有的删表判断都写为if OBJECT_ID('tempdb..表名') is not null,该逻辑是在tempdb系统临时库中查找业务表,完全不会检测当前gestionStagiaire库中的表是否存在。
这种写法会导致重复执行脚本时,判断永远为false、不会执行drop操作直接create,可能出现旧表结构残留、自增序列错乱、主键值和预期不一致的问题,最终引发主键冲突。
正确的表存在判断写法为:if OBJECT_ID('dbo.stagiaire','U') is not null drop table stagiaire。 - 全局复用DataContext导致的缓存冲突
如果你的dc(DataContext实例)是在窗体类全局定义、长期复用的,会持续追踪所有操作过的实体对象,包括之前操作失败、未成功提交的实体。当你插入新实体时,只要实体的主键值和上下文缓存中已追踪的记录值一致,就会直接触发该异常,不会触发数据库层校验。
推荐每次操作时按需实例化并释放DataContext,避免全局复用:// 每次数据库操作时新建实例,操作完成自动释放 using (var dc = new DataClasses1DataContext()) { stagiaire sr = new stagiaire(); // 字段赋值逻辑 dc.stagiaire.InsertOnSubmit(sr); dc.SubmitChanges(); } - 关联实体映射错位
你的ville表id_ville是无自增的手动赋值主键,代码中通过下拉框取id_ville值作为外键关联时,如果DBML中把外键关联的实体映射配置错位,可能导致上下文追踪的实体主键值和待插入实体的主键值混淆,触发键冲突异常。
内容的提问来源于stack exchange,提问作者Ryuk
相关产品推荐
相关产品推荐

