EF Core 5中OwnsMany值对象关系下Update操作不生效问题
EF Core 5 中OwnsMany关联值对象更新失效问题
问题场景
实体与值对象定义
public class User : Entity { public List<Skill> Skills { get; set; } } public class Skill : ValueObject { public string Name { get; private set; } }
实体映射配置
public class UserConfiguration : IEntityTypeConfiguration<User> { public void Configure(EntityTypeBuilder<User> builder) { builder .OwnsMany(user => user.Skills); } }
配置后EF会自动生成对应的Skills数据表,结构如下:
原有更新实现
使用工作单元+仓储模式,仓储层Update方法实现:
public virtual void Update(T entityToUpdate) { _context.Entry(entityToUpdate).State = EntityState.Modified; }
更新后调用工作单元的Commit方法保存:
public void Commit() { _dbContext.SaveChanges(); }
问题表现
查询User实体时可以正常获取包含Skills在内的所有属性,但执行更新操作时,仅User的非集合属性会被更新,Skills集合的变更始终无法同步到数据库。
已尝试的解决方案及对应问题
- 手动配置Skill表的主键、外键
public class UserConfiguration : IEntityTypeConfiguration<User> { public void Configure(EntityTypeBuilder<User> builder) { builder .OwnsMany(user => user.Skills, skill => { skill.WithOwner().HasForeignKey("UserId"); skill.Property<int>("Id"); skill.HasKey("id"); }); } }
修改后问题仍存在,Skills集合仍无法更新。
- 改为直接调用DbSet.Update方法更新
public virtual void Update(T entityToUpdate) { _dbSet.Update(entityToUpdate); }
执行更新时抛出并发异常:Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException : Database operation expected to affect 1 row(s) but actually affected 0 row(s).
注意:Skill为值对象,使用影子Id,推测问题根源与此特性相关。
补充代码说明
以下为完整的仓储、工作单元、上下文实现代码:
基础仓储实现
class BaseRepository<T> : IRepository<T> where T : Entity { private readonly Context _context; private readonly DbSet<T> _dbSet; public BaseRepository(Context context) { _context = context; _dbSet = context.Set<T>(); } public virtual T GetById(Guid id) => _dbSet.AsNoTracking().FirstOrDefault(x => x.Id == id); public virtual void Update(T entityToUpdate) { _context.Entry(entityToUpdate).State = EntityState.Modified; } }
工作单元实现
public class UnitOfWork : IUnitOfWork { private const int SqlObjectAlreadyExistsErrorNumber = 2627; private readonly Context _dbContext; private BaseRepository<User> _users; public UnitOfWork(Context dbContext) { _dbContext = dbContext; } public IRepository<User> Users { get { return _users ??= new BaseRepository<User>(_dbContext); } } public void Commit() { _dbContext.SaveChanges(); } }
上下文实现
public class Context : DbContext { public Context(DbContextOptions<DeribeContext> options) : base(options) { } public DbSet<User> Users { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.ApplyConfigurationsFromAssembly(typeof(DeribeContext).Assembly); base.OnModelCreating(modelBuilder); } }
内容的提问来源于stack exchange,提问作者Quico Llinares Llorens
相关产品推荐
相关产品推荐

