插入带嵌套UserPermission对象的User时触发IDENTITY_INSERT为OFF报错如何解决
错误产生原因
- 你的
UserPermission表的ID字段被设置为自增标识列(SQL Server的IDENTITY属性),默认配置下,数据库禁止向该字段手动插入指定值,除非你显式开启对应表的IDENTITY_INSERT开关。 - 当你调用
dbContext.User.Add(someUser)时,EF会默认将someUser关联的所有未被跟踪的实体(这里就是你已经赋值的UserPermission对象)标记为新增状态,执行SaveChanges时会尝试将该UserPermission对象作为新记录插入表中,你提前赋值的ID会被带入插入语句,最终触发该报错。
满足前提的解决方案(无需显式添加外键字段、无需将UserPermission属性置空)
方案1:关联现有UserPermission记录(最常用)
如果你赋值的UserPermission.ID对应的权限记录已经存在于数据库,仅需要给新增的User关联该现有权限,只需要在保存前手动修改UserPermission的实体跟踪状态即可:
dbContext.User.Add(someUser); // 告诉EF该UserPermission是已存在的记录,不需要执行插入操作 dbContext.Entry(someUser.UserPermission).State = EntityState.Unchanged; dbContext.SaveChanges();
方案2:需要插入指定ID的全新UserPermission记录
如果业务要求必须使用你手动赋值的ID作为新UserPermission记录的主键,可以临时开启对应表的IDENTITY_INSERT开关完成插入:
using var transaction = dbContext.Database.BeginTransaction(); try { // 开启UserPermission表的标识列显式插入权限 dbContext.Database.ExecuteSqlRaw("SET IDENTITY_INSERT UserPermission ON"); dbContext.User.Add(someUser); dbContext.SaveChanges(); // 插入完成后及时关闭开关 dbContext.Database.ExecuteSqlRaw("SET IDENTITY_INSERT UserPermission OFF"); transaction.Commit(); } catch { transaction.Rollback(); throw; }
注意:该方案需要当前操作的数据库账号有修改表配置的权限,且同一时间只能有一张表开启
IDENTITY_INSERT。
方案3:业务层面不需要UserPermission.ID自增
如果你所有的UserPermission记录的ID都是业务侧手动生成的,不需要数据库自增,可以直接修改模型配置关闭ID的自增属性:
// 在DbContext的OnModelCreating方法中添加如下配置 modelBuilder.Entity<UserPermission>() .Property(p => p.ID) .ValueGeneratedNever();
配置后EF会认为UserPermission的ID由业务侧生成,插入时不会再将其当做自增标识列处理,不会触发对应报错。
内容的提问来源于stack exchange,提问作者GrimReverb
相关产品推荐
相关产品推荐

