I'm a bit stumped. From what I've read setting the DbContext.AutoDetectChangesEnabled
to false
should disable change tracking requiring one to call DbContext.DetectChanges
in order to identify changes to be sent to the database.
However, it is clear from my logs below that the changes are being registered by dbContexts change tracker, even with the setting set to false.
Am I missing something?
Entity Framework Version: 5.0.0.0
DbContext class
public class ProjectContext : DbContext {
public DbSet<Project> Projects {get;set;}
}
Controller class
private ProjectContext db = new ProjectContext();
public method(){
Project p = new Project("uniqueName");
db.Configuration.AutoDetectChangesEnabled = false;
db.Projects.Add(p);
DebugChangeTracker();
db.SaveChanges();
db.Projects.First().ProjectName = "a differentName!";
DebugChangeTracker();
db.SaveChanges();
}
Logging method
private void DebugChangeTracker()
{
var path = "C:\\mypath\\";
path = path + Util.GetMsSinceEpoch().ToString() + "changeTracker.log";
using (StreamWriter sw = new StreamWriter(path))
{
var changeTracker = db.ChangeTracker;
var entries = changeTracker.Entries();
foreach (var x in entries)
{
var name = x.Entity.ToString();
var state = x.State;
sw.WriteLine("");
sw.WriteLine("***Entity Name: " + name +
"is in a state of " + state);
var currentValues = x.CurrentValues;
sw.WriteLine("***CurrentValues***");
PrintPropertyValues(currentValues,sw);
if (state != EntityState.Added)
{
sw.WriteLine("***Original Values***");
PrintPropertyValues(x.OriginalValues,sw);
}
}
}
}
First log
***Entity Name: Models.Projectis in a state of Added
***CurrentValues***
ProjectId:0
ProjectName:uniqueName
Second Log
***Entity Name: Models.Projectis in a state of Modified
***CurrentValues***
ProjectId:1
ProjectName:uniqueName
***Original Values***
ProjectId:1
ProjectName:a differentName!
In Entity Framework, change tracking is enabled by default. You can also 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.
DetectChanges in order to identify changes to be sent to the database.
By default, EF Core creates a snapshot of every entity's property values when it is first tracked by a DbContext instance. The values stored in this snapshot are then compared against the current values of the entity in order to determine which property values have changed.
EF Core change tracking works best when the same DbContext instance is used to both query for entities and update them by calling SaveChanges. This is because EF Core automatically tracks the state of queried entities and then detects any changes made to these entities when SaveChanges is called.
Setting AutoDetectChangesEnabled
to false
doesn't disable change tracking. (That's what the AsNoTracking()
extension method would do.) It just disables the automatic call of DetectChanges
that would otherwise occur in many DbContext
API methods.
But DetectChanges
isn't the only method that participates in change tracking. However, if you don't call it manually at the right places where it is needed the tracked entity states are incomplete or wrong leading to incorrectly saved data.
In your case the state Added
in the first part of your method
is expected, even with AutoDetectChangesEnabled
set to false
because you only call db.Projects.Add(p)
. (The line is missing in your code btw, but I guess it's just a copy and paste error.) Calling a method from the DbContext
API tracks changes correctly and the states in the tracker will be correct if the state was correct before the call to Add
.
Or in other words: Calling an API method doesn't turn a correct state into a wrong state. But: If AutoDetectChangesEnabled
is false
it also won't turn a wrong state into a correct state which would be the case if AutoDetectChangesEnabled
is true
.
However, in the second part of your method
you are just changing a POCO property value. After this point the change tracker state is wrong (Unchanged
) and without a call to DetectChanges
(manually or - if AutoDetectChangesEnabled
is true
- automatically in ChangeTracker.Entries
or SaveChanges
) it will never be adjusted. The effect is that the changed property value is not saved to the database.
In the last section mentioning the state Unchanged
I'm refering to my own test (and also to what I would expect). I don't know and can't reproduce why you have state Modified
.
Sorry, if this sounds all a bit confusing. Arthur Vickers can explain it better.
I find automatic change detection and the behaviour when disabling it rather difficult to understand and to master and I usually don't touch the default (AutoDetectChangesEnabled
= true
) for any tracked changes that are more complex than the simplest things (like bulk adding entities in a loop, etc.).
If someone looking for AutoDetectChangesEnabled
in Entity Framework Core you can find it under ChangeTracker
insted of Configuration
Usage like:
context.ChangeTracker.AutoDetectChangesEnabled = false;
//Do something here
context.PriceRecords.Add(newPriceRecord);
context.ChangeTracker.AutoDetectChangesEnabled = true;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With