Por que é possível enumerar uma consulta dblinq depois de ligar para DisponE () no DataContext?

StackOverflow https://stackoverflow.com/questions/2851755

  •  27-09-2019
  •  | 
  •  

Pergunta

Atualizar - A resposta é aparentemente que o dblinq não implementa Dispose() devidamente. D'HO!


O abaixo é todo tipo de enganador - Conclusão: o dblinq ainda não é (ainda) equivalente a Linqtosql, como presumi quando originalmente fiz essa pergunta. Use -o com cautela!

Estou usando o padrão de repositório com o dblinq. Meus objetos de repositório implementam IDisposable, e as Dispose() Método faz apenas coisa-calls Dispose() no DataContext. Sempre que uso um repositório, envolvi -o em um using Bloco, como este:

public IEnumerable<Person> SelectPersons()
{
    using (var repository = _repositorySource.GetPersonRepository())
    {
        return repository.GetAll(); // returns DataContext.Person as an IQueryable<Person>
    }
}

Este método retorna um IEnumerable<Person>, então, se meu entendimento estiver correto, nenhuma consulta do banco de dados realmente ocorre até Enumerable<Person> é atravessado (por exemplo, convertendo -o em uma lista ou matriz ou usando -o em um foreach loop), como neste exemplo:

var persons = gateway.SelectPersons();
// Dispose() is fired here
var personViewModels = (
    from b in persons
    select new PersonViewModel
    {
        Id = b.Id,
        Name = b.Name,
        Age = b.Age,
        OrdersCount = b.Order.Count()
    }).ToList(); // executes queries

Neste exemplo, Dispose() é chamado imediatamente após a configuração persons, que é um IEnumerable<Person>, e essa é a única vez que é chamada.

Então, três perguntas:

  1. Como é que isso funciona? Como pode ser disposto DataContext ainda consulte o banco de dados para obter resultados após o DataContext foi disposto?
  2. O que Dispose() realmente faz?
  3. Ouvi dizer que não é necessário (por exemplo, veja essa questão) para descartar um DataContext, mas minha impressão foi que não é uma má ideia. Existe algum motivo não Para descartar um dblinq DataContext?
Foi útil?

Solução

1 Como isso funciona? Como um datacontext disposto ainda pode consultar o banco de dados para obter resultados após a disposição do Datacontext?

Isto não trabalhar. Há algo que você não está nos mostrando. Acho que sua classe de repositório não descarta o DataContext corretamente/na hora certa, ou que você está escrevendo perfurialamente ToList() No final de cada consulta, que nega completamente a transformação da consulta e a execução diferida que você normalmente recebe.

Experimente o seguinte código em um aplicativo de teste, eu garantia você que vai jogar um ObjectDisposedException:

// Bad code; do not use, will throw exception.
IEnumerable<Person> people;
using (var context = new TestDataContext())
{
    people = context.Person;
}
foreach (Person p in people)
{
    Console.WriteLine(p.ID);
}

Este é o caso reprodutível mais simples possível e sempre será lançado. Por outro lado, se você escrever people = context.Person.ToList() Em vez disso, os resultados da consulta já foram enumerados lado de dentro a using Bloco, o que aposto é o que está acontecendo no seu caso.

2 O que o dispete () realmente faz?

Entre outras coisas, ele define uma bandeira indicando que o DataContext está disposto, que é verificado em todas as consultas subsequentes e causa o DataContext para jogar um ObjectDisposedException com a mensagem Object name: 'DataContext accessed after Dispose.'.

Também fecha a conexão, se o DataContext Abriu e o deixou aberto.

3 Ouvi dizer que não é necessário (por exemplo, ver essa pergunta) descartar um datacontext, mas minha impressão foi que não é uma má idéia. Existe alguma razão para não descartar um Linqtosql Datacontext?

Isto é necessário para Dispose a DataContext, como é necessário Dispose todos os outros IDisposable. Você poderia potencialmente vazar conexões se não conseguir descartar o DataContext. Você também pode vazar memória se alguma das entidades recuperadas do DataContext são mantidos vivos, pois o contexto mantém um cache de identidade interno para o padrão de unidade de trabalho que implementa. Mas mesmo que nada disso fosse o caso, Não é sua preocupação o que Dispose o método faz internamente. Suponha que faça algo importante.

IDisposable é um contrato Isso diz: "A limpeza pode não ser automática; você precisa me descartar quando terminar". Você não tem garantias de se o objeto tem ou não seu próprio finalizador que se limpa depois de você se você esquecer Dispose. As implementações estão sujeitas a alterações, e é por isso que não é uma boa idéia confiar no comportamento observado em oposição às especificações explícitas.

A pior coisa que pode acontecer se você descartar um IDisposable com um vazio Dispose O método é que você desperdiça alguns ciclos de CPU. A pior coisa que pode acontecer se você falhou para descartar um IDisposable com um implementação não trivial é que você vaza recursos. A escolha aqui é óbvia; Se você vê um IDisposable, não se esqueça de descartá -lo.

Outras dicas

"Pessoas" é uma coleção ienumerable, o DataContext (repositório) é necessário apenas para fazer a chamada .getNew.

As palavras -chave do/select/etc são açúcar sintático para métodos de extensão adicionados no espaço de nome System.linq. Esses métodos de extensão adicionam a funcionalidade IEnumerable que você está usando em sua consulta, não no DataContext. De fato, você pode fazer tudo isso sem usar o LINQ2SQL, criando programaticamente um iEnumerable para demonstrar.

Se você tentar fazer mais um repositório (Datacontext) mais chamadas usando esses objetos, é quando você receberá um erro.

A coleção IEnumerable conterá todos os registros do seu repositório, é por isso que você não precisa do DataContext para fazer a consulta.

Métodos de extensão: http://msdn.microsoft.com/en-us/library/bb383977.aspx

Métodos de extensão LINQ:http://msdn.microsoft.com/en-us/library/system.linq.enumerable_members.aspx

No fundo da API, você provavelmente verá um método usando uma API como esta:

http://msdn.microsoft.com/en-us/library/y6wy5a0f(v=vs.100).aspx

Quando o comando é executado, o objeto de conexão associado é fechado quando o objeto DataReader associado é fechado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top