首页 > 解决方案 > 实体框架核心在 SaveChanges 之前更改实体关系

问题描述

在以通用方式调用 SaveChanges 之前,有什么方法可以更新实体关系?

public class Vehicle
{
    public int Id { get; set; }
    public int OwnerId { get; set; }
    [ForeignKey("OwnerId")]
    public Person Owner { get; set; }
}

例如,我想创建新的 Person,并在生成 Id 之前将其分配给 Vehicle(在调用 SaveChanges 之前)。我知道我可以这样做:

entry.Property("OwnerId").CurrentValue = newId;

但问题是在调用之前我不知道新实体的 ID SaveChanges

我想要实现的是在所有者更改时自动创建所有者的副本,并将所有者分配给副本。当然,我必须在 SaveChanges 覆盖中以某种方式做到这一点。

就像是:

public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
{
    foreach (var entry in ChangeTracker.Entries())
    {
       foreach (var reference in entry.References)
       {
          if (reference.TargetEntry != null && reference.TargetEntry.State == EntryState.Modified)
          {
              // make a copy of target entry and update reference to it,
             // note: you can't really add new entries inside this loop as it will throw an exception, so all the adding has to be done outside
            // I would like to set this newEntity as the Owner
            var newEntity = (BaseEntity)entry.CurrentValues.ToObject();
            newEntity.Id = 0;
          }
       }
    }
    return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}

我希望它如何工作:

//would insert new Person row and update OwnerId to point to this new row
vehicle.Owner.Name = "NewName";

标签: c#entity-framework-core

解决方案


您应该更新引用,以便在没有 ID 时更新 ID:

public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
{
    foreach (var entry in ChangeTracker.Entries())
    {
       bool shouldUpdateReference = false;

       foreach (var reference in entry.References)
       {
           if (reference.TargetEntry != null && reference.TargetEntry.State == EntryState.Modified)
           {
               shouldUpdateReference = true;
           }
       }

        // I imagine this has to be done outside the foreach 
        // since you are modifying a reference and that should 
        // update the References collection
        if (shouldUpdateReference)
        {
            entity.Reference("Owner").CurrentValue = newOwner; 
        }
    }

    return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
}

推荐阅读