É possível criar um objeto DataContext do Entity Framework e descartá-lo em um bloco usando em cada um dos meus métodos CRUD?

10

Estou construindo um aplicativo wpf que implementa os seguintes recursos:

  1. Obtenha entrada do usuário e leia dados de bancos de dados
  2. faça alguns cálculos nele
  3. Apresente-o ao usuário em vários tipos de visualizações e grave as alterações novamente no db

Arquitetura proposta: Banco de Dados -> Entity Framework -> Repositório -> Lógica Comercial -> Serviço de Dados -> ViewModel

Razões para usar essa arquitetura: Vários cenários presentes no aplicativo (Várias exibições) e vários bancos de dados. Portanto, estou disposto a usar o repositório no meio para abstração.

Uma ressalva é que o contexto terá vida longa se o repositório for implementado. Para superar isso, não há problema em criar um contexto e descartá-los em um bloco using () em cada um dos métodos crud.

fique à vontade para sugerir abordagens alternativas.

Uppercut céu
fonte
Dê uma olhada neste tópico que é semelhante à sua consulta. stackoverflow.com/questions/21875816/…
Gopinath

Respostas:

16

Use um objeto DbContext por acesso a dados ou transação.

DbContexté um objeto leve; Ele foi projetado para ser usado uma vez por transação comercial. Tornar seu DbContextSingleton e reutilizá-lo em todo o aplicativo pode causar outros problemas, como problemas de simultaneidade e vazamento de memória.

DbContextimplementa essencialmente uma unidade de trabalho. Trate-o adequadamente.

Não descarte objetos DbContext.

Embora os DbContextimplementos IDisposable, você não deve descartá-lo manualmente, nem envolvê-lo em uma usingdeclaração. DbContextgerencia sua própria vida; quando sua solicitação de acesso a dados for concluída, DbContexta conexão com o banco de dados será fechada automaticamente.

Para entender por que esse é o caso, considere o que acontece quando você executa uma instrução Linq em uma coleção de entidades de a DbContext. Se você retornar um carregamento lento IQueryabledo seu método de acesso a dados, você se levantar de um gasoduto que não é realmente executada até que o cliente obriga alguns dados a partir dele (chamando FirstOrDefault(), ToList()ou iteração sobre ele).

Leitura adicional
Eu sempre tenho que chamar Dispose () nos meus objetos DbContext?
Por que você não deve usar o Singleton DataContexts no Entity Framework
Returning IEnumerable<T>vs. Os IQueryable<T>
repositórios devem retornar IQueryable?

Robert Harvey
fonte
4
Embora eu tenha certeza de que alguém apresentará algum tipo de caso excepcional para isso, honestamente não consigo criar um bom caso de uso para retornar um IQueryable não materializado de suas classes de acesso a dados. Isso apenas dá ao código de chamada a capacidade de acessar seu acesso a dados (algo que provavelmente não é necessário fazer) e estragar tudo. Dito isto, é realmente uma grande preocupação se preocupar com o uso de usingblocos? Ou simplesmente não estou pensando em algum caso em que o uso de um IQueryable, como você sugere, valeria a pena?
Becuzz #
@ Pecuzz: O DbContexté responsável por gerenciar sua própria vida. Minha sugestão é deixar fazer isso; funcionará se você estiver usando IQueryableou IEnumerable. O caso de uso mais óbvio que consigo pensar em carregamento lento é onde você retorna algum objeto ViewModel com uma coleção relacionada, mas a coleção nunca é usada (ou apenas parcialmente usada). IQueryablepermite evitar o custo de recuperar registros não utilizados.
Robert Harvey
3
Eu entendo tudo isso, é só que eu fui queimada por ter as pessoas retornando IQueryables em todo o lugar. E então, algo mais adiante na cadeia adicionou algumas inclusões ou outras coisas que resultaram em uma consulta horrivelmente ruim (da perspectiva do desempenho do banco de dados). E esse foi um bug divertido de rastrear. Como tal, tive a oportunidade de pensar se retornar uma IQueryable é uma boa ideia. E nunca consegui pensar em uma época em que valesse a pena o problema de manutenção. (continuação)
Becuzz 24/10
4
@RobertHarvey, qual é exatamente o ponto de uma camada de repositório se estiver retornando um IQueryable para o cliente? Você basicamente está dando ao cliente a opção de escrever consultas - com certeza elas não serão consultas sql, mas mesmo assim são consultas (apenas escritas usando C #) e estarão em todo o lugar. Se um repositório estiver retornando o IQueryable, você também poderá jogar fora o repositório.
CodingYoshi
8
@RobertHarvey Discordo de não descartar o DbContext e discordo do artigo referido. A idéia toda é codificar contra a interface, e a interface me diz que é IDisposable. Não vou escrever meu código com base no funcionamento interno de como a equipe da EF implementou o DbContext ou perseguir os desenvolvedores dessa equipe - eles podem alterá-lo a qualquer momento. Nem vou pedir a mim ou a outros desenvolvedores para começar a investigar o funcionamento interno de cada classe para ver se o IDisposable é realmente útil. Eu trabalhei muito para conseguir que os desenvolvedores da minha equipe se dispusessem apenas a perguntar nem sempre.
CodingYoshi
-3

Idealmente, o contexto deve ser inicializado e finalizado para uma única transação. No seu caso, o contexto deve ser instanciado no Business Logic e passado para o Repositório para leitura / gravação de dados.

Gopinath
fonte
2
Sim, porque a lógica de negócios é mais sustentável quando fortemente acoplada ao acesso a dados ... :(
TheCatWhisperer
-3

Se você chamar DbContext em cada método no seu aplicativo, ocorrerá vazamento de memória. Use uma única instância do DbContext. Veja o comentário no exemplo abaixo:

public bool IsInStock(int _ProductId)
{
  var result = false;

  try
  {
    using (var dataService = new StoreDbDataService()) // NB: This line on each method will eventually cause memory leak.
    {
      result = dataService.IsInStock(_ProductId);
    }
  }
  catch (Exception ex)
  {
    Log.LogException(ex);
  }

  return result;
}
Joseph Majase Sithole
fonte
1
Você pode explicar por que chamar DbContext causaria um vazamento de memória? O comentário na fonte não me ajuda a entendê-lo. Eu suporia que o bloco using faria com que Dispose fosse chamado no StoreDBDataService, que eventualmente limpa todos os recursos alocados, não é?
Kasper van den Berg
Este é basicamente o clipe de "permissão" de Ron Swanson, mas em código.
Dagrooms