简体   繁体   English

EF Core 在父实体保存时更新子实体

[英]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.

相关问题 EF Core:可以添加和保存父实体,但根本无法保存子实体 - EF Core: Can add and save parent entity, but fail to save child entities at all 避免使用 EF Core 在子实体上附加父实体 - Avoid attaching parent entity on child entities using EF Core EF Core子实体自动添加到父级 - EF Core child entities automatically added to parent EF Core 在循环中更新实体和子实体 - 在第一次通过时保存提交整个列表的更改 - EF Core update entity and child entities in loop - save changes commiting entire list on first pass EF Core 3.1删除具有子关系的父实体+保存更改+在新父中重用相同的子ID =并发异常 - EF Core 3.1 Removing parent entity with child relations + save changes + reuse same child id in new parent = concurrent exception 多个父实体首先在EF代码中包含一个子实体 - multiple parent Entities with one child entity in EF code first 在 EF 6 中更新父实体时如何删除子实体? - How to delete child entities when updating a parent entity in EF 6? 无法在EF4中将父实体与现有子实体一起添加 - Unable to add parent entity with existing child entities in EF4 在 EF 中更新父实体时更新子实体 - update child entities when updating a parent entity in EF 如何在 EF 中更新父实体时添加/更新子实体 - How to add/update child entities when updating a parent entity in EF
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM