EF Core+DDD中添加PersonOrg如何同步Person/Org关联集合
如何在添加PersonOrg后同步更新Person和Org的关联集合
在DDD+EF Core的多对多建模场景中,要实现PersonOrg添加后同步更新Person和Org的关联集合,核心是让聚合根自己控制状态变更,同时结合EF Core的持久化配置确保数据一致性,具体步骤如下:
1. 让聚合根维护自身的关联集合
Person和Org作为聚合根,需封装内部关联集合的修改逻辑,避免外部直接操作:
// Person聚合根 public class Person { // 私有字段,对应EF配置中设置的Field访问模式 private List<PersonOrgId> _personOrgIds = new(); // 对外暴露只读集合,保证封装性 public IReadOnlyCollection<PersonOrgId> PersonOrgIds => _personOrgIds.AsReadOnly(); // 添加关联PersonOrgId的方法 public void AddPersonOrgId(PersonOrgId personOrgId) { if (!_personOrgIds.Any(id => id.Value == personOrgId.Value)) { _personOrgIds.Add(personOrgId); } } } // Org聚合根(同Person逻辑) public class Org { private List<PersonOrgId> _personOrgIds = new(); public IReadOnlyCollection<PersonOrgId> PersonOrgIds => _personOrgIds.AsReadOnly(); public void AddPersonOrgId(PersonOrgId personOrgId) { if (!_personOrgIds.Any(id => id.Value == personOrgId.Value)) { _personOrgIds.Add(personOrgId); } } }
2. 在PersonOrg创建时触发聚合根更新
PersonOrg作为关联实体,其创建操作需联动更新对应的Person和Org聚合根,确保关联关系同步:
public class PersonOrg { public PersonId PersonId { get; private set; } public OrgId OrgId { get; private set; } public PersonOrgId Id { get; private set; } // 私有构造函数,强制通过Create方法创建实例 private PersonOrg() { } public static PersonOrg Create(PersonId personId, OrgId orgId, Person person, Org org) { var personOrgId = PersonOrgId.Create(Guid.NewGuid()); var personOrg = new PersonOrg { Id = personOrgId, PersonId = personId, OrgId = orgId }; // 触发聚合根添加关联ID person.AddPersonOrgId(personOrgId); org.AddPersonOrgId(personOrgId); return personOrg; } }
3. 完善Org的EF Core配置
和Person的配置保持一致,让EF Core自动持久化Org的PersonOrgIds集合:
// OrgConfigurations.cs public class OrgConfigurations : IEntityTypeConfiguration<Org> { public void Configure(EntityTypeBuilder<Org> builder) { builder.OwnsMany(o => o.PersonOrgIds, ib => { ib.ToTable("OrgPersonOrgIds"); ib.WithOwner().HasForeignKey("OrgId"); ib.HasKey("Id"); ib.Property(id => id.Value).HasColumnName("PersonOrgId"); }); builder.Metadata.FindNavigation(nameof(Org.PersonOrgIds))! .SetPropertyAccessMode(PropertyAccessMode.Field); } }
4. 在事务内完成所有操作
为避免数据不一致,添加PersonOrg和更新聚合根的操作必须放在同一个事务中执行:
public class PersonOrgAppService { private readonly AppDbContext _dbContext; public PersonOrgAppService(AppDbContext dbContext) { _dbContext = dbContext; } public async Task CreatePersonOrgAsync(Guid personId, Guid orgId) { using var transaction = await _dbContext.Database.BeginTransactionAsync(); try { // 获取EF上下文追踪的聚合根实例 var person = await _dbContext.Persons.FindAsync(personId); var org = await _dbContext.Orgs.FindAsync(orgId); var personIdObj = PersonId.Create(personId); var orgIdObj = OrgId.Create(orgId); // 创建PersonOrg并同步聚合根关联集合 var personOrg = PersonOrg.Create(personIdObj, orgIdObj, person, org); // 保存所有变更 _dbContext.PersonOrgs.Add(personOrg); await _dbContext.SaveChangesAsync(); await transaction.CommitAsync(); } catch { await transaction.RollbackAsync(); throw; } } }
补充说明
由于EF Core会自动追踪上下文内实体的变更,只要Person和Org实例是从当前上下文获取的,修改它们的内部集合后,SaveChangesAsync会自动将集合变更同步到对应的中间表(PersonPersonOrgIds和OrgPersonOrgIds)。
内容的提问来源于stack exchange,提问作者Gayan Dasanayake
相关产品推荐
相关产品推荐

