解决EF Core向带计算主键的SQL Server表插入数据失败问题
解决EF Core插入时尝试写入计算列D_ID的问题
问题根源
你的D_ID是SQL Server的持久化计算列,同时作为主键,但EF Core默认会认为主键需要由应用提供值,即使添加了[DatabaseGenerated]特性,也可能因为主键的特殊处理导致配置未生效,最终生成的Insert语句包含D_ID字段,导致插入失败。
解决方案:使用Fluent API明确配置(推荐)
Fluent API在处理主键+计算列的场景下比数据注解更可靠,以下是具体配置步骤:
1. 实体类定义
确保实体类中不对D_ID进行手动赋值,保持属性定义简洁:
public class TblName { public int ID { get; set; } public string D_ID { get; set; } public string NAME { get; set; } public bool? IS_ENABLED { get; set; } public string ADDRESS { get; set; } }
2. 在DbContext中配置实体
重写OnModelCreating方法,明确告诉EF Core各列的生成规则:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<TblName>(entity => { // 配置ID为自增标识列 entity.Property(e => e.ID) .ValueGeneratedOnAdd() .UseIdentityColumn(); // 配置D_ID为数据库计算列,指定计算逻辑并标记为持久化 entity.Property(e => e.D_ID) .HasComputedColumnSql("('DID' + RIGHT('000000' + CONVERT([varchar](6), [ID]), 6))", persisted: true) .ValueGeneratedOnAddOrUpdate(); // 插入/更新时均由数据库生成 // 设置D_ID为主键 entity.HasKey(e => e.D_ID); // 配置NAME字段的唯一约束 entity.HasIndex(e => e.NAME).IsUnique(); // 配置IS_ENABLED的默认值(与数据库默认值保持一致) entity.Property(e => e.IS_ENABLED) .HasDefaultValue(true); }); }
3. 插入新记录的正确方式
插入时不要给D_ID和ID赋值,由数据库自动生成:
var newItem = new TblName { NAME = "示例名称", ADDRESS = "示例地址" // IS_ENABLED可省略,数据库会使用默认值1 }; await _context.TblNames.AddAsync(newItem); await _context.SaveChangesAsync();
数据注解的替代方案(可选)
如果你更倾向于使用数据注解,确保实体类配置正确,且DbContext中没有覆盖相关配置:
public class TblName { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Computed)] public string D_ID { get; set; } [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID { get; set; } [Required] [MaxLength(50)] public string NAME { get; set; } [DefaultValue(true)] public bool? IS_ENABLED { get; set; } [MaxLength(2000)] public string ADDRESS { get; set; } }
注意:这种方式在部分EF Core版本中可能因为主键的特殊逻辑导致配置不生效,因此优先推荐Fluent API方案。
额外注意事项
- 如果之前已经生成过迁移文件,需要重新生成迁移并更新数据库,确保配置生效。
- 确认数据库中的
D_ID列确实是计算列,没有被手动修改为普通列。
内容的提问来源于stack exchange,提问作者amjee
相关产品推荐
相关产品推荐

