2013-05-31 9 views
28

Ich bin ein wenig ratlos. Von dem, was ich gelesen habe, sollte das Setzen von DbContext.AutoDetectChangesEnabled auf false die Änderungsverfolgung deaktivieren, die DbContext.DetectChanges aufrufen muss, um Änderungen zu identifizieren, die an die Datenbank gesendet werden sollen.DbContext AutoDetectChangesEnabled auf falsche Erkennung von Änderungen gesetzt

Es ist jedoch klar, meine Protokolle unten, dass die Änderungen von dbContexts registriert werden Tracker ändern, auch mit der Einstellung auf false gesetzt.

Fehle ich etwas?

Entity Framework Version: 5.0.0.0

DbContext Klasse

public class ProjectContext : DbContext { 
    public DbSet<Project> Projects {get;set;} 
} 

Controller-Klasse

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 Methode

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); 
       } 
      } 
     } 
    } 

Erste 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! 

Antwort

38

AutoDetectChangesEnabled zu false Einstellung nicht ändern Tracking deaktivieren. (Das ist, was die Erweiterungsmethode AsNoTracking() tun würde.) Sie deaktiviert nur den automatischen Aufruf von DetectChanges, der sonst in vielen API-Methoden DbContext auftreten würde.

Aber DetectChanges ist nicht die einzige Methode, die in der Änderungsverfolgung beteiligt. Wenn Sie sie jedoch nicht manuell an den richtigen Stellen aufrufen, an denen sie benötigt wird, sind die Status der nachverfolgten Entitäten unvollständig oder falsch und führen zu falsch gespeicherten Daten.

In Ihrem Fall der Staat Added im ersten Teil Ihrer method wird erwartet, auch mit AutoDetectChangesEnabled Satz zu false, weil Sie nur db.Projects.Add(p) nennen. (Die Zeile fehlt in Ihrem Code btw, aber ich denke, es ist nur ein Kopieren und Einfügen Fehler.) Aufruf einer Methode von der DbContext API verfolgt Änderungen korrekt und die Zustände im Tracker werden korrekt sein, wenn der Zustand vor dem Aufruf an korrekt war Add.

Oder mit anderen Worten: eine API-Methode einen korrekten Zustand in einen falschen Zustand nicht Aufruf nicht einschalten. Aber: Wenn AutoDetectChangesEnabledfalse ist, wird es auch keinen falschen Zustand in einen korrekten Zustand schalten, was der Fall wäre, wenn AutoDetectChangesEnabledtrue ist.

jedoch im zweiten Teil Ihrer method Sie sind nur einen POCO-Eigenschaftswert zu ändern. Nach diesem Punkt ist der Status des Änderungs-Trackers falsch (Unchanged) und ohne einen Aufruf von DetectChanges (manuell oder - wenn AutoDetectChangesEnabled ist true - automatisch in oder SaveChanges) wird es nie angepasst werden. Dies hat zur Folge, dass der geänderte Eigenschaftswert nicht in der Datenbank gespeichert wird.

Im letzten Abschnitt, der den Zustand Unchanged erwähnt, beziehe ich mich auf meinen eigenen Test (und auch auf das, was ich erwarten würde). Ich weiß nicht und kann nicht reproduzieren, warum Sie den Status Modified haben.

Sorry, wenn das alles ein wenig verwirrend klingt. Arthur Vickers can explain it better.

Ich finde automatische Änderungserkennung und das Verhalten, wenn es ziemlich schwierig, zu verstehen, zu deaktivieren und zu meistern und ich berühren in der Regel nicht den Standard (AutoDetectChangesEnabled = true) für jede Änderungen verfolgt, die komplexer sind als die einfachsten Dinge (wie das Hinzufügen von Entitäten in einer Schleife, usw.).

+0

Ich hatte zu lesen über das ein paar Mal, aber das nicht beantworten helfen, meine Frage ziemlich viel, danke! Entschuldigung wegen des Kopier- und Einfügefehlers; Ich werde die Frage für die Nachwelt aktualisieren. – Jesse

+1

Leider ist "bulk das Hinzufügen von Entitäten in einer Schleife", wenn die Änderungsverfolgung deaktiviert werden soll. Es ist eine _massive_ Beschleunigung (Stichprobenumfang von 1, getestet in meiner App, aber es war der einzige Unterschied zwischen zwei Läufen, die ~ 3000 Zeilen hinzufügten). –

+1

@EdS .: Bulk-Hinzufügen ist eines der "einfachsten Dinge", die ich meinte, wo ich die automatische Änderungserkennung * deaktivieren * würde. – Slauma

1

nach Entity Framework Automatic Detect Changes's Article

sie sagte:

Sie erhebliche Leistungsverbesserungen erhalten kann durch off in some cases

Blick auf dieses Beispiel aus diesem Artikel drehen

using (var context = new BloggingContext()) 
{ 
    try 
    { 
     context.Configuration.AutoDetectChangesEnabled = false; 

     // Make many calls in a loop 
     foreach (var blog in aLotOfBlogs) 
     { 
      context.Blogs.Add(blog); 
     } 
    } 
    finally 
    { 
     context.Configuration.AutoDetectChangesEnabled = true; 
    } 
} 

Dieser Code vermeidet unnötige Aufrufe an DetectChanges, die beim Aufruf der Methoden DbSet.Add und SaveChanges aufgetreten wären.

+0

Wenn Sie es wieder in den endgültigen Block, macht es automatisch tun, was es getan hätte, wenn es gewesen wäre, aber schneller? –

2

Wenn jemand für AutoDetectChangesEnabled in Entity Framework-Core suchen Sie es unter ChangeTracker insted Configuration

Usage wie finden:

context.ChangeTracker.AutoDetectChangesEnabled = false; 

//Do something here 
context.PriceRecords.Add(newPriceRecord); 

context.ChangeTracker.AutoDetectChangesEnabled = true;