Introduction
Entity Framework is able to track the changes made to entities and their relations, so the correct updates are made on the database when the SaveChanges method of context is called. This is a key feature of the Entity Framework. Change tracking happens through snapshot change tracking for the most POCO entity type. In the snapshot change tracking, a snapshot of the entity is taken when it loads or is attached by context and this snapshot of the entity is used to track changes on an entity by comparing the current value with the original value.
The Change Tracking tracks changes while adding new record(s) to the entity collection, modifying or removing existing entities. Then all the changes are kept by the DbContext level. These track changes are lost if they are not saved before the DbContext object is destroyed.
Automatic change tracking is enabled by default in Entity Framework. We can disable change tracking by setting the AutoDetectChangesEnabled property of DbContext to false. If this property is set to true then the Entity Framework maintains the state of entities.
using (Entities Context = new Entities())
{
Context.Configuration.AutoDetectChangesEnabled = true;
}
Example
Suppose I have a table called “DepartmentMaster” and I am doing some operations like create, update and delete. Now I want to track all changes on this entity.
![]()
the following is the initial test data of the Department Master table.
![]()
Code for Getting Changed entity using Change Tracker of Context
The DbContext.ChangeTracker.Entries() method returns all the entities tracked by the DbContext. These entities are in the form of DbEntityEntry. Using the DbEntityEntry.Entity Property, we can determine the tracked entity with its state. The DbEntityEntry instances always contain a non-null Entity and also Stub entities and Relationship entries are not a part of these DbEntityEntry instances, so we do not need to do further filtration for these.
The following code can help us determine the tracked entities. Here the AuditLog class is useful for storing the details of the tracked entities, like table name, column name, action type, original value, and new value.
public class AuditLog
{
public string State { get; set; }
public string TableName { get; set; }
public string RecordID { get; set; }
public string ColumnName { get; set; }
public string NewValue { get; set; }
public string OriginalValue { get; set; }
}
public static List<AuditLog> GetAuditLogData(Entities Context)
{
List<AuditLog> AuditLogs = new List<AuditLog>();
var changeTrack = Context.ChangeTracker.Entries().Where(p => p.State == EntityState.Added || p.State == EntityState.Deleted || p.State == EntityState.Modified);
foreach (var entry in changeTrack)
{
if (entry.Entity != null)
{
string entityName = string.Empty;
string state = string.Empty;
switch (entry.State)
{
case EntityState.Modified:
entityName = ObjectContext.GetObjectType(entry.Entity.GetType()).Name;
state = entry.State.ToString();
foreach (string prop in entry.OriginalValues.PropertyNames)
{
object currentValue = entry.CurrentValues[prop];
object originalValue = entry.OriginalValues[prop];
if (!currentValue.Equals(originalValue))
{
AuditLogs.Add(new AuditLog
{
TableName = entityName,
State = state,
ColumnName = prop,
OriginalValue = Convert.ToString(originalValue),
NewValue = Convert.ToString(currentValue),
});
}
}
break;
case EntityState.Added:
entityName = ObjectContext.GetObjectType(entry.Entity.GetType()).Name;
state = entry.State.ToString();
foreach (string prop in entry.CurrentValues.PropertyNames)
{
AuditLogs.Add(new AuditLog
{
TableName = entityName,
State = state,
ColumnName = prop,
OriginalValue = string.Empty,
NewValue = Convert.ToString(entry.CurrentValues[prop]),
});
}
break;
case EntityState.Deleted:
entityName = ObjectContext.GetObjectType(entry.Entity.GetType()).Name;
state = entry.State.ToString();
foreach (string prop in entry.OriginalValues.PropertyNames)
{
AuditLogs.Add(new AuditLog
{
TableName = entityName,
State = state,
ColumnName = prop,
OriginalValue = Convert.ToString(entry.OriginalValues[prop]),
NewValue = string.Empty,
});
}
break;
default:
break;
}
}
}
return AuditLogs;
}

John NguyenPosted Mar 24, 2020, 2:50 AM
Why wont this work if you modify the Department Code this way?......var deptUpdate = new DepartmentMaster() { DepartmentId = "1", Code = "123" }; context.DepartmentMasters.Attach(deptUpdate); context.Entry(deptUpdate).Property(x => x.Code).IsModified = true; context.SaveChanges();
Mahipatsinh ParmarPosted Jun 28, 2019, 6:50 AM
Original values and current values are the same when executing the code
Athar Ali KhanPosted Jan 12, 2017, 4:06 AM
How to implement the same on Entity framework using generic repository pattern?
Kan LuPosted Jun 3, 2015, 1:42 AM
RecordID was defined but never used.
sonubaba mananiPosted Apr 13, 2015, 4:45 PM
gr8, good article with detail info