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.
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
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;
}
Olá Andrey!
Neste caso, quando implemento o padrão Repositorio, eu abro e fecho o contexto para cada operação. Não deixo o repositório responsável por definir em qual momento a instância do contexto será fechada. Dê uma olhada nesse link: https://github.com/FerHenrique/PantheonRepository
Talvez lhe ajude, mas ainda esta em construção.
[]s e obrigado por postar!
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?
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!
cache de entidades. era só para saber se este cache perdura mesmo apos o GC ter recolhido o objeto do tipo DbContext?
Oi Andrey,
Não perdura. Por isso sempre uso o bloco using.
[]s!
blz. então não tem necessidade de chamar o Dispose do contexto no finalizador. obrigado
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!
[…] Mais sobre o assunto pode ser encontrado neste outro post: DbContext e o ObjectContext – Não deixe seus dados em memória […]
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.
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!
Fernando, agora fiquei confuso, hehehe
Estava dando uma olhada nesse artigo do Jon Gallant (http://blog.jongallant.com/2012/10/do-i-have-to-call-dispose-on-dbcontext/) ele repassa algumas informações da equipe do EF, em que eles falam que não é necessário chamar o Dispose(), pois o garbage collector é que se responsabiliza de eliminar esse lixo.
Oq vc acha dessa abordagem?