Konrad
Konrad

Reputation: 7198

Entity Framework Core change entity relation before SaveChanges

Is there any way to update entity relation before calling SaveChanges in generic way?

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

For example I would like to create new Person, and assign it to Vehicle before Id is generated (before calling SaveChanges). I know I can do it like:

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

But the problem is that I don't know the Id of the new entity before calling SaveChanges.

What I'm trying to achieve is to automatically create a copy of the Owner when it changes, and assign the Owner to the copy. For sure I have to do it somehow inside SaveChanges override.

Something like:

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);
}

How I want it to work:

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

Upvotes: 0

Views: 1453

Answers (1)

Camilo Terevinto
Camilo Terevinto

Reputation: 32058

You should update the reference so that the Id is updated when you don't have the 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);
}

Upvotes: 2

Related Questions