EF Core .ToJson()拥有实体变更追踪:修改子实体如何关联父实体
解决EF Core拥有实体变更时关联主实体的问题
我之前把PostgreSQL JSON列的映射方式从旧的特性标记:
public class Order { public Guid Id { get; set; } [Column(TypeName = "jsonb")] public CustomerDTO Customer { get; set; } }
换成了EF Core模型构建器的.ToJson()拥有实体映射,现在遇到个问题:修改Customer对象时,Order实体不会被标记为Modified,但Customer会。我重写了SaveChangesAsync来填充发件箱,希望只要Order的任何部分变更,就把整个Order放进发件箱,有没有不用遍历导航属性就能拿到父实体的方法?
不用遍历导航属性的两种解决方法
方法一:直接获取主实体并加入发件箱
利用EF Core变更追踪里的实体元数据,判断当前实体是否是拥有实体,再直接拿到它的主实体:
修改你的SaveChangesAsync方法:
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) { var trackedEntries = ChangeTracker.Entries().ToList(); var outboxEntities = new HashSet<object>(); foreach (var entry in trackedEntries) { if (entry.State == EntityState.Added || entry.State == EntityState.Modified) { // 处理拥有实体,找到对应的主实体 if (entry.Metadata.IsOwned()) { var ownerEntry = ChangeTracker.Entries() .FirstOrDefault(e => e.Entity == entry.EntityEntry.Owner); if (ownerEntry != null) { outboxEntities.Add(ownerEntry.Entity); } } else { outboxEntities.Add(entry.Entity); } } } // 把收集到的实体添加到发件箱 foreach (var entity in outboxEntities) { // 这里写添加到Outbox的逻辑 } return base.SaveChangesAsync(cancellationToken); }
方法二:主动标记主实体为Modified
如果希望主实体也被标记为Modified,后续按原有逻辑处理就行:
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) { // 先处理所有变更的拥有实体,标记主实体为Modified var modifiedOwnedEntries = ChangeTracker.Entries() .Where(e => e.Metadata.IsOwned() && e.State == EntityState.Modified); foreach (var ownedEntry in modifiedOwnedEntries) { var ownerEntry = ChangeTracker.Entries() .FirstOrDefault(e => e.Entity == ownedEntry.EntityEntry.Owner); if (ownerEntry != null && ownerEntry.State != EntityState.Added) { ownerEntry.State = EntityState.Modified; } } // 按原来的逻辑处理新增/修改的实体 foreach (var e in ChangeTracker.Entries()) { if (e.State == EntityState.Added || e.State == EntityState.Modified) { // 添加到Outbox } } return base.SaveChangesAsync(cancellationToken); }
核心说明
entry.Metadata.IsOwned():快速判断当前实体是否是拥有实体entry.EntityEntry.Owner:直接获取拥有实体所属的主实体实例- 用
HashSet是为了避免同一个主实体被多次添加到发件箱(比如多个拥有实体同时变更的情况)
这样不用手动遍历导航属性,就能确保发件箱里包含完整的Order实体,只要它的任何部分(包括Customer)发生了变更。
内容的提问来源于stack exchange,提问作者Display Name
相关产品推荐
相关产品推荐

