DbContext AutoDetectChangesEnabled set to false detecting changes


Estoy un poco perplejo. Por lo que he leído configurar DbContext.AutoDetectChangesEnabled a false debería desactivar el seguimiento de cambios que requiere llamar a DbContext.DetectChanges para identificar los cambios que se enviarán a la base de datos.

Sin embargo, está claro a partir de mis registros a continuación que los cambios están siendo registrados por DbContexts change tracker, incluso con la configuración establecida en false.

¿Me estoy perdiendo algo?

Versión de Entity Framework: 5.0.0.0

Clase DbContext

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

Clase de controlador

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étodo de registro

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

Primer registro

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

Segundo Log

***Entity Name: Models.Projectis in a state of Modified
***CurrentValues***
ProjectId:1
ProjectName:uniqueName
***Original Values***
ProjectId:1
ProjectName:a differentName!
Author: Hakam Fostok, 2013-05-31

3 answers

Establecer AutoDetectChangesEnabled a false no deshabilita el seguimiento de cambios. (Eso es lo que haría el método de extensión AsNoTracking().) Solo deshabilita la llamada automática de DetectChanges que de otra manera ocurriría en muchos métodos API DbContext.

Pero DetectChanges no es el único método que participa en el seguimiento de cambios. Sin embargo, si no lo llama manualmente en los lugares correctos donde se necesita, los estados de entidad rastreados están incompletos o son incorrectos, lo que conduce a datos guardados incorrectamente.

En su caso, el estado Added en la primera parte de su method se espera, incluso con AutoDetectChangesEnabled establecido en false porque solo llama db.Projects.Add(p). (La línea falta en su código por cierto, pero supongo que es solo un error de copiar y pegar.) Llamar a un método desde la API DbContext rastrea los cambios correctamente y los estados en el rastreador serán correctos si el estado era correcto antes de la llamada a Add.

O en otras palabras: Llamar a un método API no convierte un estado correcto en un estado incorrecto. Pero: Si AutoDetectChangesEnabled es false tampoco lo hará convertir un estado incorrecto en un estado correcto, lo que sería el caso si AutoDetectChangesEnabled es true.

Sin embargo, en la segunda parte de su method solo está cambiando un valor de propiedad POCO. Después de este punto, el estado del rastreador de cambios es incorrecto (Unchanged) y sin una llamada a DetectChanges (manualmente o - si AutoDetectChangesEnabled es true - automáticamente en ChangeTracker.Entries o SaveChanges) nunca se ajustará. El efecto es que el valor de propiedad cambiado no se guarda en la base de datos.

En la última sección mencionando la estado Unchanged Me estoy refiriendo a mi propia prueba (y también a lo que esperaría). No lo sé y no puedo reproducir por qué tienes estado Modified.

Lo siento, si esto suena todo un poco confuso. Arthur Vickers puede explicarlo mejor.

Encuentro la detección automática de cambios y el comportamiento al deshabilitarlo bastante difícil de entender y dominar y generalmente no toco el valor predeterminado (AutoDetectChangesEnabled = true) para cualquier cambio rastreado que sea más complejo que las cosas más simples (como la adición masiva de entidades en un bucle, etc.).

 43
Author: Slauma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-31 20:39:40

De acuerdo con Entity Framework Automatic Detect Changes's Article

Dijeron:

Puede obtener mejoras significativas en el rendimiento si lo desactiva en some cases

Mira este ejemplo de ese artículo

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

Este código evita llamadas innecesarias a DetectChanges que se habrían producido al llamar a los métodos DbSet.Add y SaveChanges.

 3
Author: Basheer AL-MOMANI,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-02 09:52:54

Si alguien busca AutoDetectChangesEnabled en Entity Framework Core, lo puede encontrar en ChangeTracker insted de Configuration

Uso como:

context.ChangeTracker.AutoDetectChangesEnabled = false;

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

context.ChangeTracker.AutoDetectChangesEnabled = true;
 2
Author: Jiri Houzvicka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-27 09:44:12