4

Need a centralized solution to get the resulting Entity as persisted to the Db, potentially inside the SaveChangesAsync() and SaveChanges() methods of my DbContext or via an event listener.

Need resulting entity value to contain all new .ValueGeneratedOnAdd[Updated/etc]() properties. i.e.RowVersion, Updated, etc..

The purpose is to communicate the before and after of the Entity for concurrency communication.

This is what I have thus far: This first method incurrs an extra, unnecessary Db hit.

public override async Task<int> SaveChangesAsync(
        CancellationToken cancellationToken = new CancellationToken() )
{
    var before = ChangeTracker.Entries().AsEnumerable().First();

    var res = await base.SaveChangesAsync(cancellationToken);

    /* ********************************************************           
       I can do the following, but this results in an extra 
       DbQuery. I know that if this were a  consumer 
       method with entity, after I called SaveChangesAsync() it 
       would have the new resulting values.  Just not sure how 
       to access here inside SaveChangesAsync()?
       ********************************************************** */
    await ChangeTracker.Entries().AsEnumerable().First().ReloadAsync(); 
    /* ********************************************************
       ^ Additionally, ReloadAsync has a "Note, however, that an 
       Added entity may not yet have had its permanent key value 
       created. 
       ********************************************************** */
    var after = ChangeTracker.Entries().AsEnumerable().First();

    return res;
}

Additionally I have subscribed to the new state change events Tracked and StateChagned that are mentioned or linked on github issue EntityFrameworkCore - Lifecycle hooks #626: For Ex:

public class StateListener : IEntityStateListener
{
    public void StateChanging(InternalEntityEntry entry, EntityState newState)
    {
        Console.WriteLine(
            "  Changing {0} from {1} to {2}.",
            entry.Entity.GetType().Name, entry.EntityState, newState);
    }

    public void StateChanged(InternalEntityEntry entry, 
        EntityState oldState, bool fromQuery)
    {
        Console.WriteLine(
            "  Changed {0} to {1} from {2}.",
            entry.Entity.GetType().Name, entry.EntityState, oldState);
    }

    public void StateChanged(InternalEntityEntry entry, EntityState oldState,
        bool skipInitialFixup, bool fromQuery)
    {
        Console.WriteLine(
            "  Changed {0} from {1} to {2}.",
            entry.Entity.GetType().Name, oldState, entry.EntityState);
    }
}

However the newState and the InternalEntityEntry in StateChanged all posess the values that should save and not the new values that are set by the Db, such RowVersion, Changed etc..

ttugates
  • 5,818
  • 3
  • 44
  • 54

1 Answers1

1

Answer for those with similar search - Upon asking this question I had a fundamental misunderstanding. I believed an entity persisted to the Db would have all its values updated on SaveChanges[Async](). I believed this because that is the behavior of Primary Keys as described in "How can I get Id of inserted entity in Entity framework?"

This is not the case for properties that are .ValueGeneratedOnAdd[Updated/etc]() and are not RowVersion or PrimaryKeys.

With this understanding, any possible solution presumably would require a query to the Db. I considered adding such a query to the OnCommandExecuting and then working with result in OnCommandExecuted but abandoned due to its nature.

ttugates
  • 5,818
  • 3
  • 44
  • 54