ChangeLog OriginalValue same as CurrentValue on EF Core Update Entity

.net-core c# entity-framework entity-framework-core


I have a problem with updating entities in EF Core and then logging those changes in a table. Technologies used are:

  • .NET Core 2.2.0
  • EF Core 2.2.3

So, I want to get an entity from the database, edit it in front-end and then update it on the backend and save those changes into the database. On top of that, I have a table called ChangeLogs where the most important fields are From (mapped from OldValues) and To (mapped from CurrentValues). Well, those two fields are the same (meaning they have the exact same values, the new values) and the situation goes like this:

  1. I get the entity from the database like this

    _context.Anomalies .Include(a => a.Asset) .FirstOrDefaultAsync(a => a.Id == anomalyId)

  2. Edit the entity in front-end and then make a PUT request to update it;

  3. Update the entity:

    In order for the Update() to work, first I have to call this: _context.DetachAllEntities(); Otherwise I get an error saying that an entity with the same Id is already being tracked. Then call Update() and SaveChanges():

    _context.Anomalies.Update(anomaly); _context.SaveChanges();

    The anomaly object is the one from the request.

  4. For the ChangeLog part, I overridden the SaveChanges() method, following this example, and the Old/Original and New/Current values are set like this: auditEntry.OldValues[propertyName] = property.OriginalValue; auditEntry.NewValues[propertyName] = property.CurrentValue;

    Basically this goes through all entries from ChangeTracker, creates an AuditEntry and after the base.SaveChanges() it will go back and set the EntityId for that AuditEntry because you don't have it before save changes (this is in case you add a new entity, for update nothing happens after save changes).

The Update() method is working, changes are reflected in the database. But the only problem is with ChangeLogs, the entry from ChangeTracker.Entries() does not know the OldValues.

I admit that I don't fully understand the tracking system used by EF, but I suppose it should help me updating entities and not create problems. Because I know calling _context.DetachAllEntities();is not correct. I tried to use AsNoTracking() and drop the DetachAllEntities() but the result seems to be the same. I thought about taking the dbEntity, copy each field from request entity to database entity and then Update(dbEntity) but that seems like a lot of work to do for basically a small benefit. My Anomaly entity has a lot of navigation properties, it would be difficult to create a copy method for it and to maintain it.

The DetachAllEntities() is defined like this:

public static void DetachAllEntities(this DbContext context)
    var entries = context.ChangeTracker.Entries().ToList();
    foreach (var entry in entries)
        entry.State = EntityState.Detached;

DbContext is set to Scoped lifetime, managers as well.

I tried to use the Auditing method from this tutorial as well, but the result is the same.

I have a concern that the whole Update process is not done right and therefore this problems..

UPDATE I have created a sample project to exemplify this problem. You can check the source code on bitbucket. The README hase some more info on this

I serialized the objects retrieved from the context.

With Tracking on the LEFT <====> With NO tracking on the RIGHT With Tracking on the LEFT <====> With NO tracking on the RIGHT

Any advice, opinion, new idea, comment is welcomed. Thank you!

5/22/2019 12:34:31 PM

Popular Answer

enter image description here

I think your problem is here. Because the two objects exist in different contexts, it is fundamentally a different object. If you change your code so that you retrieve the entity from the database, update its values, then use that object to pass to the SaveChangesAndAudit() method. You will get the result you are expecting. I have adjusted the code in the attached screenshot. You will also come up against a fundamental problem that most developers find, and that is mapping objects - tools like Automapper make your life easier with this sort of thing - so if your entities are big, its worth taking a look at that to help ;-)

5/22/2019 1:56:38 PM

Related Questions


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow