2013-05-31 12 views
28

Jestem trochę zakłopotany. Z tego, co przeczytałem, ustawienie DbContext.AutoDetectChangesEnabled na wartość false powinno wyłączyć śledzenie zmian, wymagające wywołania DbContext.DetectChanges w celu zidentyfikowania zmian, które mają zostać wysłane do bazy danych.DbContext AutoDetectChangesEnabled ustawiony na fałszywe wykrywanie zmian

Jednak z moich logów poniżej wynika, że ​​zmiany są rejestrowane przez moduł śledzenia dbContexts, nawet jeśli ustawienie ma wartość false.

Czy brakuje mi czegoś?

Entity Framework Version: 5.0.0.0

klasa DbContext

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

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

metoda rejestrowania

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

Pierwszy dziennik

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

drugie Log

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

Odpowiedz

38

Ustawianie AutoDetectChangesEnabled do false nie wyłącza śledzenie zmian. (Tak właśnie zrobiłaby metoda rozszerzenia AsNoTracking()). Po prostu wyłącza automatyczne wywoływanie z DetectChanges, które w innym przypadku wystąpiłoby w wielu metodach API DbContext.

Ale DetectChanges nie jest jedyną metodą, która uczestniczy w śledzeniu zmian. Jeśli jednak nie wywołasz tego ręcznie w odpowiednich miejscach, w których jest to potrzebne, stany obiektów śledzonych są niekompletne lub błędne, co prowadzi do nieprawidłowo zapisanych danych.

W twoim przypadku oczekuje się stan Added w pierwszej części swojej method, nawet z AutoDetectChangesEnabled zestaw do false bo tylko zadzwonić db.Projects.Add(p). (Brakuje linii w kodzie btw, ale myślę, że to tylko błąd kopiowania i wklejania.) Wywołanie metody z ścieżek API API zmienia się poprawnie, a stany w trackerze będą poprawne, jeśli stan był poprawny przed wywołaniem Add.

Innymi słowy: wywołanie metody interfejsu API nie zmienia prawidłowego stanu w nieprawidłowy stan. Ale: Jeśli AutoDetectChangesEnabled jest false, to również nie zmieni niewłaściwego stanu w prawidłowy stan, który byłby, gdyby AutoDetectChangesEnabled jest true.

Jednak w drugiej części twojego method zmieniasz tylko wartość właściwości POCO. Po tym punkcie stan śledzenia zmian jest nieprawidłowy (Unchanged) i bez wywołania do DetectChanges (ręcznie lub - jeśli AutoDetectChangesEnabled jest true - automatycznie w ChangeTracker.Entries lub SaveChanges), nigdy nie zostanie zmieniony. Efekt jest taki, że zmieniona wartość właściwości nie jest zapisywana w bazie danych.

W ostatniej sekcji dotyczącej stanu Unchanged mówię o moim własnym teście (a także o tym, czego bym się spodziewał). Nie wiem i nie mogę odtworzyć, dlaczego masz stan Modified.

Przepraszam, jeśli to brzmi trochę myląco. Arthur Vickers can explain it better.

znajdę automatyczne wykrywanie zmian i zachowanie podczas wyłączania to raczej trudne do zrozumienia i opanowania, a ja zwykle nie dotykać domyślną (AutoDetectChangesEnabled = true) dla dowolnego śledzone zmiany, które są bardziej skomplikowane niż najprostszych rzeczy (jak jednostki dodające masę w pętli itp.).

+0

musiałem przeczytać, że kilka razy, ale to nie pomaga odpowiedzieć na moje pytanie dość, dzięki! Przykro nam z powodu błędu kopiowania i wklejania; zaktualizuję pytanie dla potomności. – Jesse

+1

Niestety, "zbiorcze dodawanie podmiotów w pętli" ma miejsce wtedy, gdy chcesz wyłączyć śledzenie zmian. Jest to szybkie przyspieszenie (wielkość próby 1, testowana w mojej aplikacji, ale była to jedyna różnica między dwoma biegami dodającymi ~ 3000 wierszy). –

+1

@EdS .: Dodawanie zbiorcze jest jedną z "najprostszych rzeczy", o których mi chodziło, gdzie faktycznie * mogę * wyłączyć automatyczne wykrywanie zmian. – Slauma

1

według Podmiotu Framework Automatic Detect Changes's Article

mówili:

można uzyskać znaczne poprawę wydajności obracając ją off w some cases

Spójrz na ten przykład od tego artykułu

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

Kod ten pozwala uniknąć niepotrzebnych połączeń z numerem DetectChanges, które wystąpiłyby podczas wywoływania metod DbSet.Add i .

+0

Jeśli włączysz je ponownie w bloku finally, robi to automatycznie zrobić to, co by zrobił, gdyby był włączony, ale szybszy? –

2

Jeśli ktoś szuka AutoDetectChangesEnabled w Entity Framework rdzenia można go znaleźć pod ChangeTracker insted Configuration

Wykorzystanie takich jak:

context.ChangeTracker.AutoDetectChangesEnabled = false; 

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

context.ChangeTracker.AutoDetectChangesEnabled = true;