2013-05-31 7 views
28

Sono un po 'perplesso. Da quello che ho letto l'impostazione del DbContext.AutoDetectChangesEnabled su false dovrebbe disattivare il rilevamento delle modifiche che richiedono uno a chiamare DbContext.DetectChanges al fine di individuare le modifiche da inviare al database.DbContext AutoDetectChangesEnabled impostata su false rilevare i cambiamenti

Tuttavia, dai miei registri di seguito è chiaro che le modifiche vengono registrate da dbContexts cambia traccia, anche se l'impostazione è impostata su false.

Mi manca qualcosa?

Entity Framework Version: 5.0.0.0

classe DbContext

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

classe Controller

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

metodo registrazione

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

primo registro

***Entity Name: Models.Projectis in a state of Added 
***CurrentValues*** 
ProjectId:0 
ProjectName:uniqueName 

Seconda Log

***Entity Name: Models.Projectis in a state of Modified 
***CurrentValues*** 
ProjectId:1 
ProjectName:uniqueName 
***Original Values*** 
ProjectId:1 
ProjectName:a differentName! 

risposta

38

Impostazione AutoDetectChangesEnabled-false non disabilita il rilevamento delle modifiche. (È quello che farebbe il metodo di estensione AsNoTracking().) Disabilita semplicemente la chiamata automatica di DetectChanges che altrimenti si verificherebbe in molti metodi API DbContext.

Ma il DetectChanges non è l'unico metodo che partecipa al rilevamento delle modifiche. Tuttavia, se non si chiama manualmente al posto giusto in cui è necessario gli stati di entità cingolati sono errati o incompleti che porta al salvati in modo non corretto dei dati.

Nel tuo caso è previsto lo stato Added nella prima parte del tuo method, anche con AutoDetectChangesEnabled set per false perché si chiama solo db.Projects.Add(p). (La linea manca nel tuo codice btw, ma suppongo che sia solo un errore di copia e incolla.) Chiamare un metodo dall'API DbContext tiene traccia delle modifiche correttamente e gli stati nel tracker saranno corretti se lo stato era corretto prima della chiamata a Add.

In altre parole: la chiamata di un metodo API non trasforma uno stato corretto in uno stato errato. Ma: se AutoDetectChangesEnabled è false, inoltre, non trasformerà uno stato errato in uno stato corretto che sarebbe il caso se AutoDetectChangesEnabled è true.

Tuttavia, nella seconda parte del tuo method stai semplicemente cambiando un valore di proprietà POCO. Dopo questo punto lo stato del tracker delle modifiche è errato (Unchanged) e senza una chiamata a DetectChanges (manualmente o - se AutoDetectChangesEnabled è true - automaticamente in ChangeTracker.Entries o SaveChanges) non verrà mai regolato. L'effetto è che il valore della proprietà modificata non viene salvata nel database.

Nell'ultima sezione che menziona lo stato Unchanged Mi riferisco al mio test (e anche a quello che mi aspetterei). Non lo so e non riesco a riprodurre il motivo per cui si dispone di stato Modified.

Siamo spiacenti, se questo suona un po 'di confusione. Arthur Vickers can explain it better.

trovo rilevamento cambio automatico e il comportamento quando disabilitarlo piuttosto difficile da comprendere e padroneggiare e io di solito non toccare il valore di default (AutoDetectChangesEnabled = true) per qualsiasi modifica rilevata che sono più complessi di quanto le cose più semplici (come il bulk che aggiunge entità in un loop, ecc.).

+0

Ho dovuto leggere oltre che un paio di volte, ma che aiuta a rispondere alla mia domanda un bel po ', grazie! Mi dispiace per l'errore di copia e incolla; aggiornerò la domanda per i posteri. – Jesse

+1

Sfortunatamente, "l'aggiunta di entità in un loop", è quando si desidera disabilitare il rilevamento delle modifiche. È un _massive_ speedup (dimensione del campione pari a 1, testato nella mia app, ma era l'unica differenza tra due esecuzioni che aggiungevano ~ 3000 righe). –

+1

@EdS .: L'aggiunta di massa è una delle "cose ​​più semplici" intendevo dire che in realtà avrei * disabilitato * il rilevamento automatico dei cambiamenti. – Slauma

1

in base alle entità Framework Automatic Detect Changes's Article

dissero:

si possono ottenere significativi miglioramenti delle prestazioni girandolo fuori in some cases

un'occhiata a questo esempio da tale articolo

Questo codice evita chiamate non necessarie a DetectChanges che si sarebbero verificate durante la chiamata ai metodi DbSet.Add e SaveChanges.

+0

Se lo riattivi nel blocco finally, lo fa automaticamente fare ciò che avrebbe fatto se fosse stato acceso, ma più veloce? –

2

Se qualcuno in cerca di AutoDetectChangesEnabled in Entity Framework Core si può trovare sotto ChangeTracker invece di Configuration

Uso come:

context.ChangeTracker.AutoDetectChangesEnabled = false; 

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

context.ChangeTracker.AutoDetectChangesEnabled = true;