EF查询返回空Guid主键,调用SaveChanges触发DbUpdateConcurrencyException如何解决
问题根因与解决方案
核心问题是EF Core查询返回的Invoice实体Id属性未被正确赋值为数据库中的值,默认保持Guid.Empty,导致SaveChanges时生成的更新语句用WHERE Id = '00000000-0000-0000-0000-000000000000'作为筛选条件,匹配不到行,因此抛出DbUpdateConcurrencyException异常。
导致Id属性未被正确赋值的常见原因及对应解决方案如下:
- 未显式指定主键,约定识别失效
EF Core默认会将名为Id/类名+Id的属性识别为主键,但存在自定义构造函数、局部模型配置等场景时可能触发约定失效。你可以任选一种方式显式指定主键:- 在
Id属性上加[Key]数据注解:
[Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public Guid Id { get; set; }- 在
OnModelCreating的Invoice配置中新增主键声明:
modelBuilder.Entity<Invoice>(entity => { // 新增这行显式指定主键 entity.HasKey(e => e.Id); entity.Property(e => e.Id).ValueGeneratedOnAdd(); entity.Property(e => e.InvoiceNumber); }); - 在
- 自定义构造函数干扰EF Core实体物化逻辑
EF Core会优先匹配参数名和列名对应的构造函数做实体实例化,你的自定义构造函数中存在名为id的参数,但是你将该参数赋值给了FileId而非实体的Id属性,就算加了无参构造也可能存在绑定优先级问题。可通过以下方式解决:- 若该自定义构造函数非必须,可直接删除,仅保留无参构造
- 若需要保留,可显式指定EF Core使用无参构造实例化实体(EF Core 3.0+支持):
modelBuilder.Entity<Invoice>() .HasConstructorBinding( ConstructorBindingFactory.CreateBinding( typeof(Invoice).GetConstructor(Type.EmptyTypes), new PropertyParameterBinding[0])); - 局部配置覆盖了映射规则
检查OnModelCreatingPartial方法中的配置,确认没有将Id属性标记为Ignore,也没有将其他属性指定为Invoice的主键。
你可以先输出生成的查询SQL验证:如果查询语句中没有包含Id列,说明Id未被EF Core识别为映射属性,优先检查映射配置;如果查询语句包含Id列但实体Id仍为空,优先检查构造函数绑定逻辑。
内容的提问来源于stack exchange,提问作者Philippe Balleydier
相关产品推荐
相关产品推荐

