EF7 - How to get values from DbSet before change

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

Question

I try to get the value of entity that stored in DbSet before it was changed by code and before it was saved. However, when I try to get it with LINQ Single statement I get the changed value. I'm using EF7.

Here's the code:

DbSet<Entity> dbSet = Context.dbSet;
Entity ent = dbSet.Single(x => x.Id == id);
ent.FirstName = "New name";
Entity entityBeforeChange = dbSet.Single(x => x.Id == id);  //here I want to get entity with old values, if that's important I just need to read it without modifying this instance

Context.SaveChanges();

Hope I was clear enough and can get some help

Accepted Answer

You can Detach an entity from the context. Keep in mind that you'll have to pull it from the context before you update the other, attached entity.

DbSet<Entity> dbSet = Context.dbSet;
Entity ent = dbSet.Single(x => x.Id == id);
Entity entityBeforeChange = dbSet.Single(x => x.Id == id); 
Context.Entry(entityBeforeChange).State = EntityState.Detached; // severs the connection to the Context
ent.FirstName = "New name";

Context.SaveChanges();

Expert Answer

Here is a code I use from my audit library.

EF7

using (var ctx = new TestContext())
{
    Entity ent = entity.Single(x => x.Id == id);
    entity.FirstName = "New name";

    context.ChangeTracker.DetectChanges();

    // Find your entry or get all changed entries
    var changes = context.ChangeTracker.Entries().Where(x => x.State == EntityState.Modified);

    foreach (var objectStateEntry in changes)
    {
        AuditEntityModified(audit, objectStateEntry, auditState);
    }
}

public static void AuditEntityModified(Audit audit, AuditEntry entry, EntityEntry objectStateEntry)
{
    foreach (var propertyEntry in objectStateEntry.Metadata.GetProperties())
    {
        var property = objectStateEntry.Property(propertyEntry.Name);

        if (entry.Parent.CurrentOrDefaultConfiguration.IsAudited(entry.ObjectStateEntry, propertyEntry.Name))
        {
            entry.Properties.Add(new AuditEntryProperty(entry, propertyEntry.Name, property.OriginalValue, property.CurrentValue));
        }
    }
}

EF6

using (var ctx = new TestContext())
{
    Entity ent = entity.Single(x => x.Id == id);
    entity.FirstName = "New name";

    var entry = ((IObjectContextAdapter)ctx).ObjectContext.ObjectStateManager.GetObjectStateEntry(entity);
    var currentValues = entry.CurrentValues;
    var originalValues = entry.OriginalValues;

    AuditEntityModified(originalValues, currentValues);
}

public static void AuditEntityModified(DbDataRecord orginalRecord, DbUpdatableDataRecord currentRecord, string prefix = "")
{
    for (var i = 0; i < orginalRecord.FieldCount; i++)
    {
        var name = orginalRecord.GetName(i);
        var originalValue = orginalRecord.GetValue(i);
        var currentValue = currentRecord.GetValue(i);

        var valueRecord = originalValue as DbDataRecord;
        if (valueRecord != null)
        {
            // Complex Type
            AuditEntityModified(valueRecord, currentValue as DbUpdatableDataRecord, string.Concat(prefix, name, "."));
        }
        else
        {
            if (!Equals(currentValue, originalValue))
            {
                // Add modified values
            }
        }
    }
}

Edit: The complete source code can be found in my GitHub repository: https://github.com/zzzprojects/EntityFramework-Plus

Library Website: http://entityframework-plus.net/



Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why