Entity Framework - DetectChanges

Conforme prometido no post anterior, vou resumir o funcionamento do método DetectChanges do EntityFramework. Para isso, vamos tomar como exemplo a classe de uma entidade Aluno conforme abaixo:

public class Aluno
{
    public int AlunoId { get; set; }
    public string Nome { get; set; }
    public int TurmaId { get; set; }
    public virtual Turma Turma { get; set; }    
}

Não há nenhum trecho no código acima que notifique e mantenha o controle de alteração dessa entidade.

Quando executamos uma alteração das propriedades de Aluno usando o seguinte código

using (var context = new EntityContext())
{
    var aluno = context.Alunos.Single(a=>a.Nome == "Maria Luiza");
    aluno.Nome = "Ana Maria";
    context.SaveChanges();
}

O EF sabe que precisará enviar um comando de "update" ao banco de dados fazendo um snapshot das propriedades no momento em que o o objeto é obtido do banco de dados e comparando com seu estado final na execução do método SaveChanges().

No exemplo, modificamos a propriedade Nome, o método DetectChanges foi chamado pelo SaveChanges para escanear e comparar as propriedades para posteriormente executar o update.

O método DetectChanges também é responsável por fazer outras verificações importantes. Vejamos o exemplo de relacionamento abaixo:
Banco-De-Dados-Aluno-Turma

Maria Luiza faz parte da Turma de ASP NET MVC5. Vamos supor que eventualmente haja uma tentativa de alteração indevida da propriedade TurmaId na entidade Aluno:

using (var context = new EntityContext())
{
    try
    {
        var aluno = context.Alunos.Single(a=>a.Nome == "Maria Luiza");
        aluno.TurmaId = 3;  // FK - TurmaId inexistente
        context.SaveChanges();
    }
    catch (Exception erro)
    {
        Console.WriteLine(erro.Message);
    }
}

O DetectChanges irá retornar uma exceção, pois uma de suas funções é verificar a existência da nova FK.
Banco-De-Dados-Aluno-Turma-Exception

- O que aconteceria se eu desabilitasse o DetectChanges ?

Vamos testar setando false no método AutoDetectChangesEnabled:

using (var context = new EntityContext())
{
    try
    {
        context.Configuration.AutoDetectChangesEnabled = false; // Desabilitando AutoDetectChanges
        var aluno = context.Alunos.Single(a=>a.Nome == "Maria Luiza");
        aluno.Nome = "Ana Maria";
        aluno.TurmaId = 3;
        Console.WriteLine(context.Entry(aluno).State);
        context.SaveChanges();
    }
    catch (Exception erro)
    {
        Console.WriteLine(erro.Message);
    }
}

Executando o código acima, o EF não atualizou a entidade com um novo nome pois ele não conhecia as propriedades modificadas e simplesmente não fez nada. Nem ao menos gerou uma exceção em relação à propriedade inexistente TurmaId. Vejam que o estado da entidade aluno foi retornado como "Unchanged".
Banco-De-Dados-Aluno-Turma-Unchanged

Enfim, não é recomendável desabilitar o AutoDetectChangesEnabled. No meu post anterior, desativei pra ganhar performance em um teste onde eu executava um insert de 10.000 novos registros numa tabela simples. Especificamente nesse contexto de teste, torná-lo off, resultou em uma expressiva redução do tempo que era de 40 segundos em média para aproximadamente 3 segundos.

Sugiro a leitura do blog do Arthur Vickers, desenvolvedor que atua no time de desenvolvimento do Entity Framework, que escreveu uma série de 4 posts sobre o tema - Link: Secrets of DetectChanges Part 1: What does DetectChanges do?

Até a próxima!
Abs

2 thoughts on “Entity Framework - DetectChanges

  1. Valeu Bruno! Existem algumas maneiras de tunar o EF. Vou tentar criar alguns cenários e testar desempenho antes e depois de aplicar o tunning. Irei postar em seguida.

    Obrigado!

  2. Excelente dica, é muito importante sabermos usar o entity, pois já vi muita gente usando ele da maneira errada e dizendo que a culpa no Entity pois ele é "lento".

    Post mais dicas sobre Entity Framework.

Leave a Reply

Your email address will not be published. Required fields are marked *

This blog is kept spam free by WP-SpamFree.