DbContext e o ObjectContext – Não deixe seus dados em memória!

O DbContext e o ObjectContext são duas classes responsáveis por gerenciar e acompanhar alterações em instâncias de classes no modelo, estas classes também gerenciam a conexão e o contexto de transação das operações com o banco de dados.

É importante assegurar que qualquer recurso associado com estes objetos seja limpo da memória quando não mais necessários, pois ao longo de cada execução é mantido um CACHE das instâncias de objetos recuperadas nas consultas. Se mantivermos a instância de nosso contexto por muito tempo ativa, executando consultas atrás de consultas, corremos o risco de consumir mais memória do que o necessário.

Para resolver esta questão, tanto a classe DbContext quanto a classe ObjectContext implementam a interface IDisposable, que inclui o método Dispose(), responsável por eliminar recursos utilizados pela instância corrente que não sejam mais necessários.

Como boa prática, propõem-se que sempre sejam limpos da memória os recursos que não forem mais necessários, por isso é indicado a chamada ao método Dispose().

Para automatizar a execução do método Dispose(), e assim liberar recursos da memória, recomenda-se a utilização do bloco USING, que irá na primeira linha criar uma instância de uma classe que implemente a interface IDisposable e que no fim do bloco irá executar (de maneira implícita) o método Dispose(). O exemplo abaixo ilustra o uso do bloco USING.

using

Se a sua aplicação não faz uso do bloco USING, então execute o método Dispose() explicitamente ao fim de cada transação com o banco de dados, para assegurar a limpeza de memória das instâncias de objetos contidas no contexto e que não são mais necessárias.

Outra prática errada que me deparo de vez em quando é o uso de classes Singleton que encapsulam uma instância de um contexto de acesso a dados. Este erro é bastante grave, pois devidos as características de utilização da classe Singleton, esta instância do contexto de acesso a dados apenas será limpa da memória quando a aplicação for finalizada. Este é um cenário péssimo, pois a quantidade de registros mantidos em memória de forma desnecessária é muito grande, impedindo a execução ótima da aplicação.
Obrigado pela atenção!

[]s e até o próximo!

Por
Fernando Henrique Inocêncio Borba Ferreira
Microsoft Most Valuable Professional – Data Platform Development

Anúncios

12 comentários

  1. então se eu fosse criar uma classe generica, para interagir com DbContext , e esta classe tivesse métodos de Dispose() ela seria desta maneira:

    private DbContext _contexto = new DbContext();

    //aqui ficam métods para o CRUD

    private bool disposed = false; //verificar se DisposeAuxiliar() já foi chamado

    public void Dispose()
    {
    DisposeAuxiliar();
    GC.SuppressFinalize(this); //Suprimir finalizador
    }

    ~RepositorioEF() //Finalizador
    {
    DisposeAuxiliar();
    }

    private void DisposeAuxiliar()
    {
    if (!this.disposed)
    {
    if (_contexto != null)
    {
    _contexto.Dispose(); //Dispose do Contexto
    }
    }

    disposed = true;
    }

  2. fernando so mais uma dúvida, quando realizamos consultas no banco com o auxilio do DbContext estas consultas ficam em cache não é? Quando o GC coleta o objeto com o qual estavamos realizando estas consultas na base, esse cache q não tiver sido limpo com o Dispose() será eliminado na coleta de lixo?

    1. Olá Andrey,
      Existem diferentes tipos de Cache no EF, mas o Cache de entidades retornadas perdura até o Dispose da instância do seu contexto.

      Que tipo de cenário vc esta enfrentando?

      []s!

      1. cache de entidades. era só para saber se este cache perdura mesmo apos o GC ter recolhido o objeto do tipo DbContext?

      2. blz. então não tem necessidade de chamar o Dispose do contexto no finalizador. obrigado

      3. Oi Andrey,
        A necessidade de executar o dispose é evitar que vc trabalhe com dados desatualizados e o consumo exagerado de memória, deixando seu acesso a dados mais lentos.

        E o uso do cache de entidades esta relacionado com o acesso a entidades durante blocos de transaçōes.

        []s!

  3. Algumas respostas aqui estão erradas, supondo que pretende inserir vários dados usando a mesma transação, a forma como sugere utilizar o EF trará problemas, pois cada operação passa a ser atómica.

    A transação apenas é aberta no momento em que é invocado o apply changes, originando a execução de todos os statements sql necessários para sincronizar o contexto com o banco de dados, e no final fazendo commit, garantindo assim atomicidade num Set de operações.

    O contexto deverá ser inicializado no início do Set de operações a executar e fechado no final, podendo utilizar ou não o using para o efeito.

    1. Olá MnRosa.
      Sim, neste cenário que vc detalhou realmente é necessário abrir apenas uma instância de contexto para inclusão de todos os itens. Mas, por favor, note que em momento algum eu cito que cada operação corresponde a uma tarefa de inclusão, na verdade cada operação consiste de um conjunto de tarefas.

      Além disso, Veja que o post deste link (https://ferhenriquef.com/2013/10/13/entity_framework_melhores_praticas_performance_desempenho/) vai ao encontro do seu comentário no tópico 5.

      Obrigado por comentar.
      []s!

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.