web-dev-qa-db-fra.com

DbContext AutoDetectChangesEnabled défini sur faux détection des modifications

Je suis un peu perplexe. D'après ce que j'ai lu en définissant le DbContext.AutoDetectChangesEnabled à false devrait désactiver le suivi des modifications nécessitant un appel à DbContext.DetectChanges afin d'identifier les modifications à envoyer à la base de données.

Cependant, il ressort clairement de mes journaux ci-dessous que les modifications sont enregistrées par dbContexts change tracker, même avec le paramètre défini sur false.

Suis-je en train de manquer quelque chose?

Version d'Entity Framework: 5.0.0.0

Classe DbContext

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

Classe de contrôleur

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

Méthode d'enregistrement

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

Premier journal

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

Deuxième journal

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

La définition de AutoDetectChangesEnabled sur false ne désactive pas le suivi des modifications. (C'est ce que ferait la méthode d'extension AsNoTracking().) Elle désactive simplement l'appel automatique de DetectChanges qui se produirait autrement dans de nombreuses méthodes d'API DbContext.

Mais DetectChanges n'est pas la seule méthode qui participe au suivi des modifications. Cependant, si vous ne l'appelez pas manuellement aux bons endroits où cela est nécessaire, les états des entités suivies sont incomplets ou incorrects, ce qui entraîne des données incorrectement enregistrées.

Dans votre cas, l'état Added dans la première partie de votre method est attendu, même avec AutoDetectChangesEnabled défini sur false car vous n'appelez que db.Projects.Add(p). (La ligne est manquante dans votre code btw, mais je suppose que c'est juste une erreur de copier-coller.) L'appel d'une méthode à partir de l'API DbContext suit correctement les changements et les états du tracker seront corrects si l'état correct avant l'appel à Add.

Ou en d'autres termes: l'appel d'une méthode API ne transforme pas un état correct en un mauvais état. Mais: si AutoDetectChangesEnabled est false, cela ne transformera pas non plus un mauvais état en un état correct, ce qui serait le cas si AutoDetectChangesEnabled est true.

Cependant, dans la deuxième partie de votre method, vous modifiez simplement une valeur de propriété POCO. Après ce point, l'état du suivi des modifications est incorrect (Unchanged) et sans appel à DetectChanges (manuellement ou - si AutoDetectChangesEnabled est true - automatiquement dans ChangeTracker.Entries ou SaveChanges) il ne sera jamais ajusté. L'effet est que la valeur de propriété modifiée n'est pas enregistrée dans la base de données.

Dans la dernière section mentionnant l'état Unchanged je me réfère à mon propre test (et aussi à ce que j'attendrais). Je ne sais pas et ne peux pas reproduire pourquoi vous avez l'état Modified.

Désolé, si cela vous semble un peu déroutant. Arthur Vickers peut mieux l'expliquer.

Je trouve la détection automatique des modifications et le comportement lors de la désactivation plutôt difficiles à comprendre et à maîtriser et je ne touche généralement pas la valeur par défaut (AutoDetectChangesEnabled = true) pour les modifications suivies qui sont plus complexes que les choses les plus simples (comme l'ajout en masse d'entités dans une boucle, etc.).

54
Slauma

Si quelqu'un recherche AutoDetectChangesEnabled dans Entity Framework Core, vous pouvez le trouver sous ChangeTracker insted de Configuration

Utilisation comme:

context.ChangeTracker.AutoDetectChangesEnabled = false;

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

context.ChangeTracker.AutoDetectChangesEnabled = true;
9
Jiri Houzvicka

selon l'entité article de Framework Automatic Detect Changes

ils ont dit:

vous pouvez obtenir des améliorations significatives des performances en le désactivant dans some cases

regardez cet exemple de cet article

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

Ce code évite les appels inutiles à DetectChanges qui se seraient produits lors de l'appel de DbSet.Add et SaveChanges méthodes.

5