¿Por qué es posible enumerar una consulta DbLinq después de llamar a Dispose () en el DataContext?

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

  •  27-09-2019
  •  | 
  •  

Pregunta

Actualizar - La respuesta es aparentemente que DbLinq no implementa Dispose() correctamente. D'oh!


La continuación es todo tipo de engañar - En pocas palabras: DbLinq no es (todavía) equivalente a LinqToSql, ya que asumí cuando originalmente hice esta pregunta. Utilizarlo con precaución!

Estoy utilizando el patrón de repositorio con DbLinq. Mis objetos del repositorio implementan IDisposable, y el método Dispose() lo hace único - llamadas Dispose() en el DataContext. Cada vez que utilice un repositorio, que lo envuelve en un bloque using, como esto:

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

Este método devuelve un IEnumerable<Person>, así que si mi entendimiento es correcta, no consulta de la base de datos en realidad se lleva a cabo hasta que se recorre Enumerable<Person> (por ejemplo, mediante la conversión a una lista o matriz o mediante su uso en un bucle foreach), como se en este ejemplo:

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

En este ejemplo, Dispose() se llama inmediatamente después de establecer persons, que es un IEnumerable<Person>, y esa es la única vez que se llama a.

Por lo tanto, tres preguntas:

  1. ¿Cómo funciona esto? ¿Cómo puede un DataContext dispuestos todavía consultar la base de datos de resultados después de la DataContext se ha dispuesto?
  2. ¿Qué Dispose() realmente?
  3. He oído que no es necesario (por ejemplo, véase esta pregunta ) para disponer de un DataContext, pero mi impresión es que no es una mala idea. ¿Hay alguna razón no para disponer de un DataContext DbLinq?
¿Fue útil?

Solución

  

1 ¿Cómo funciona esto? ¿Cómo puede un DataContext dispuestos todavía consultar la base de datos de resultados después de la DataContext se ha dispuesto?

no trabajo. Hay algo que no nos estás mostrando. Supongo que, o bien la clase repositorio no disponer adecuadamente el DataContext / en el momento adecuado, o que usted está escribiendo perfunctorily ToList() al final de cada consulta, que niega completamente la transformación de consulta y ejecución diferida recibe normalmente.

Trate el código siguiente en una aplicación de prueba, I Garantía que va a lanzar una 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 es el caso reproducible más simple posible, y siempre va a tirar. Por otro lado, si usted escribe people = context.Person.ToList() lugar, a continuación, los resultados de la consulta ya se han enumerado dentro de bloque using, que voy a apuesta es lo que está pasando en su caso.

  

2 ¿Qué hace Dispose () en realidad hacer?

Entre otras cosas, se establece un indicador que indica que la DataContext está dispuesto, que se comprueba en cada consulta posterior y hace que el DataContext a lanzar una ObjectDisposedException con el mensaje Object name: 'DataContext accessed after Dispose.'.

También cierra la conexión, si el DataContext abrió y la dejó abierta.

  

3 He oído que no es necesario (por ejemplo, véase esta pregunta) para disponer de un DataContext, pero mi impresión es que no es una mala idea. ¿Hay alguna razón para no disponer de un LinqToSql DataContext?

es necesario Dispose la DataContext, ya que es necesario Dispose cada dos IDisposable. Usted podría filtrarse conexiones si usted no puede disponer el DataContext. También podría perder memoria si alguna de las entidades recuperadas del DataContext se mantienen con vida, ya que el contexto mantiene una caché interna de identidad para el patrón de unidad de trabajo que implementa. Pero incluso si nada de esto fuera el caso, no es su preocupación lo que hace el método Dispose internamente. Supongamos que lo hace algo importante.

IDisposable es un contrato que dice: "la limpieza puede no ser automático, que hay que deshacerse de mí cuando haya terminado." No tiene garantías de si el objeto tiene su propio finalizador que limpia después de que si se olvida de Dispose. Implementaciones están sujetos a cambios, por lo que no es una buena idea confiar en el comportamiento observado en contraposición a las especificaciones explícitas.

Lo peor que puede suceder si usted dispone de un IDisposable con un método Dispose vacío es que se pierda un par de ciclos de CPU. Lo peor que puede pasar si fallar para desechar una IDisposable con un aplicación no trivial es que de tener fugas recursos. La elección aquí es obvia; si usted ve un IDisposable, no se olvide de deshacerse de él.

Otros consejos

"personas" es una colección IEnumerable, el DataContext (repositorio) sólo es necesaria para realizar la llamada .GetNew.

la de / seleccionar / etc palabras clave son el azúcar sintáctica para los métodos de extensión añadido en el espacio de nombres System.Linq. Estos métodos de extensión añadir la funcionalidad IEnumerable que está utilizando en su consulta, no el DataContext. De hecho, se puede hacer todo esto sin necesidad de utilizar LINQ2SQL en absoluto, por programáticamente la creación de un IEnumerable de demostrar.

Si intenta realizar cualquier repositorio más (DataContext) llama el uso de estos objetos, que es cuando usted recibirá un error.

La colección IEnumerable contendrá todos los registros de su repositorio, es por eso que no requieren la DataContext para hacer la consulta.

Los métodos de extensión: http://msdn.microsoft.com/en- es / library / bb383977.aspx

métodos de extensión LINQ: http://msdn.microsoft.com/en-us/ biblioteca / system.linq.enumerable_members.aspx

En el interior del API, es probable que vea un método que utiliza una API como éste:

http://msdn.microsoft. com / es-es / library / y6wy5a0f (v = VS.100) .aspx

Cuando se ejecuta el comando, el objeto de conexión asociado se cierra cuando el objeto DataReader asociado está cerrado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top