[英]EF Core upsert child entities upon parent entity save
I have a DDD aggregate with User as root and Appointment as the child records.我有一个 DDD 聚合,其中 User 作为根,Appointment 作为子记录。 I want, when I save a User in my repository, the existing child appointments of the User are updated and the child appointment which do not exist in the database be inserted.
我想,当我在我的存储库中保存一个用户时,更新该用户的现有子约会并插入数据库中不存在的子约会。
I have for each entity a domain class and a persistence class
我为每个实体都有一个域 class 和一个持久性 class
I have read this post on the matter and I think I understand what the accepted answer explained, so I went with the following logic:我已经阅读了这篇关于此事的帖子,我想我理解接受的答案解释了什么,所以我遵循以下逻辑:
public async Task Update(IApplicationUserWithAppointments domainUserEntity)
{
ApplicationUserEntity persistenceUserEntity = await FindEntityById(domainUserEntity.Id);
IDictionary<Guid, AppointmentEntity> appointmentEntitiesById =
persistenceUserEntity.Appointments
.ToDictionary(appointmentEntity => appointmentEntity.Id, appointmentEntity => appointmentEntity);
persistenceUserEntity.UserName = domainUserEntity.UserName;
persistenceUserEntity.Password = domainUserEntity.Password;
persistenceUserEntity.FirstName = domainUserEntity.FirstName;
persistenceUserEntity.LastName = domainUserEntity.LastName;
persistenceUserEntity.Role = domainUserEntity.Role;
persistenceUserEntity.Validated = domainUserEntity.Validated;
persistenceUserEntity.Appointments = domainUserEntity.Appointments
.Select(appointment => BuildOrUpdateAppointmentEntity(appointmentEntitiesById, appointment))
.ToList();
this.context.Users.Update(persistenceUserEntity);
}
private static AppointmentEntity BuildOrUpdateAppointmentEntity(IDictionary<Guid, AppointmentEntity> appointmentEntitiesById,
Appointment appointment)
{
if (!appointmentEntitiesById.ContainsKey(appointment.Id))
{
return new AppointmentEntity(appointment);
}
AppointmentEntity appointmentEntity = appointmentEntitiesById[appointment.Id];
appointmentEntity.State = appointment.State.Name;
appointmentEntity.DateTime = appointment.DateTime;
return appointmentEntity;
}
The logic is that I retrieve the user entity from the database with its appointments (to avoid detached entity error).逻辑是我从数据库中检索用户实体及其约会(以避免分离实体错误)。 Then, I map the appointment entity, updating those which exist and creating the new one.
然后,我 map 约会实体,更新现有实体并创建新实体。
This logic works well for the update of existing appointment records, but for the insertion of new appointments records, the following unit test fails:此逻辑适用于更新现有约会记录,但对于插入新约会记录,以下单元测试失败:
public async Task Update_ChildRecord_InsertChildRecordInDb()
{
// Given
ApplicationUserEntity entity = await this.dbDataFactory.InsertValidatedLifeAssistant();
var repository = new ApplicationUserRepository(this.context, factory);
entity.Appointments.Add(new AppointmentEntity()
{
Id = Guid.NewGuid(),
State = "Planned",
DateTime = DateTime.Today.AddDays(3)
});
// When
await repository.Update(entity.ToDomainEntity(new AppointmentStateFactory()));
await repository.Save();
// Then
entity = await this.context
.Users
.Include(u => u.Appointments)
.FirstAsync(item => item.Id == entity.Id);
(await this.context.Appointments.CountAsync()).Should().Be(1);
}
With the following error:出现以下错误:
The database operation was expected to affect 1 row(s), but actually affected 0 row(s);
数据库操作预计影响1行,但实际影响0行; data may have been modified or deleted since entities were loaded.
自加载实体以来,数据可能已被修改或删除。 See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.
有关理解和处理乐观并发异常的信息,请参阅http://go.microsoft.com/fwlink/?LinkId=527962 。
On the Save
call of the update.在更新的
Save
调用上。
I don't understand why my logic is not working.我不明白为什么我的逻辑不起作用。 Thank you in advance
先感谢您
After a lot of debugging, and thank to a github post I realised that my problem was that my child record had already an Id generated, and EF Core did not expected it to.经过大量调试,并感谢 github 的帖子,我意识到我的问题是我的子记录已经生成了一个 ID,而 EF Core 并没有预料到它。 I solved my problem with by using
ValueGeneratedNever()
in my onModelCreating
model definition.我通过在
onModelCreating
model 定义中使用ValueGeneratedNever()
解决了我的问题。 Ex:前任:
modelBuilder.Entity<AppointmentEntity>().HasKey(appointment => appointment.Id);
modelBuilder.Entity<AppointmentEntity>().Property(appointment => appointment.Id).ValueGeneratedNever();
modelBuilder.Entity<AppointmentEntity>().Property(appointment => appointment.State);
modelBuilder.Entity<AppointmentEntity>().Property(appointment => appointment.DateTime);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.