EF Core 8中通过导航属性添加关联数据引发并发异常问题
问题原因分析
你遇到的问题核心在于EF Core将手动赋值Guid主键的LocalizedEmotionInfo实例判定为已存在于数据库中的实体,因此执行了UPDATE语句而非预期的INSERT语句,最终因为数据库中没有对应Id的记录,触发了并发异常。
具体逻辑:
- 你手动给
LocalizedEmotionInfo.Id赋值了Guid.NewGuid(),而EF Core默认对Guid类型主键的处理规则是:如果由用户手动赋值,会认为该实体是已存在于数据库的“已跟踪实体”,而非需要插入的新实体。 - 当通过导航属性
emotion.LocalizedInfos.Add(localizedEmotionInfo)添加时,EF Core尝试更新这条“已存在”的记录,但数据库中并没有该Guid对应的行,因此出现“预期影响1行实际0行”的异常。
解决方案
有两种可行的处理方式:
1. 配置EF Core自动生成Guid主键
修改LocalizedEmotionInfo的主键配置,让数据库自动生成Guid值:
方式一:通过DataAnnotation特性修改实体类
public class LocalizedEmotionInfo { [Required] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] // 新增该特性 public Guid Id { get; set; } // 其他属性保持不变 }
方式二:通过Fluent API修改配置类
internal sealed class LocalizedEmotionInfoConfiguration : IEntityTypeConfiguration<LocalizedEmotionInfo> { public void Configure(EntityTypeBuilder<LocalizedEmotionInfo> builder) { builder.HasKey(e => e.Id); // 新增该行配置 builder.Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); builder.HasIndex(e => new { e.EmotionId, e.Lcid }) .IsUnique(); } }
修改后,创建实例时无需手动赋值Id,EF Core会自动生成并执行INSERT操作:
var localizedEmotionInfo = new LocalizedEmotionInfo() { // 移除Id赋值 Lcid = "en-EN", LocalizedName = "Anger", LocalizedDesciption = "Some emotion", };
2. 手动标记实体为新增状态
如果必须手动赋值Guid主键,可以在添加到导航属性后,显式告知EF Core该实体是新增的:
emotion.LocalizedInfos.Add(localizedEmotionInfo); // 标记实体为新增状态 _context.Entry(localizedEmotionInfo).State = EntityState.Added; await _context.SaveChangesAsync();
或者直接将实体添加到上下文集合:
_context.LocalizedEmotionInfos.Add(localizedEmotionInfo); await _context.SaveChangesAsync();
补充说明
EF Core对主键的跟踪逻辑:
- 自增整数主键默认是数据库生成,用户手动赋值会触发异常(除非特殊配置)。
- Guid主键默认是
DatabaseGeneratedOption.None(用户手动赋值),此时EF Core会默认认为手动赋值的Id对应的实体已存在于数据库,因此执行UPDATE操作。
这就是通过导航属性添加时出现UPDATE而非INSERT的根本原因。
内容的提问来源于stack exchange,提问作者Ackdari
相关产品推荐
相关产品推荐

