Supongamos que tengo ese pseudocódigo usando algún pseudo ORM (bueno, en mi caso es Linq2Db).

static IEnumerable<A> GetA()
{
  using (var db = ConnectionFactory.Current.GetDBConnection())
  {
     return from a in db.A
            select a;
  }
}
static B[] DoSmth()
{
  var aItems = GetA();
  if (!aItems.Any())
    return null;
  return aItems.Select(a => new B(a.prop1)).ToArray();
}

¿Cuándo se cerrará Connection en db? ¿Estaría cerrado en absoluto en ese caso? ¿Qué conexión se cerraría: las del uso de la declaración o las de la expresión lambda? El compilador .NET está creando una clase anónima para lambdas, por lo que copiará la conexión a esa clase. ¿Cuándo se cerraría esa conexión?

De alguna manera logré obtener Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached. materialicé consultas y la excepción desapareció. Pero me pregunto cómo funciona esto.

7
nikita 27 dic. 2016 a las 00:33

3 respuestas

La mejor respuesta

Esto depende completamente de su ORM. Si la eliminación de ConnectionFactory.Current.GetDBConnection() cierra la conexión, nunca podrá enumerar el resultado. Si no cierra la conexión (y algo más lo hace) podría funcionar dependiendo de si alguien más ha cerrado la conexión.

En cualquier caso, probablemente no desee devolver un enumerable no enumerado de algo que crea y elimina la conexión.

Enumere la colección antes de cerrarla, por ejemplo:

static IEnumerable<A> GetA()
{
  using (var db = ConnectionFactory.Current.GetDBConnection())
  {
     return (from a in db.A
            select a).ToArray();
  }
}

O controlar la conexión en el nivel que enumera los resultados, por ejemplo:

static IEnumerable<A> GetA(whatevertype db)
{
   return from a in db.A
          select a;
}
static B[] DoSmth()
{
  using (var db = ConnectionFactory.Current.GetDBConnection())
  {
    var aItems = GetA(db);
    if (!aItems.Any())
      return null;
    return aItems.Select(a => new B(a.prop1)).ToArray();
  }
}
4
Not loved 27 dic. 2016 a las 11:42

Linq2db libera la conexión cuando cierra su objeto de conexión. En su ejemplo, sucede cuando deja el bloque using y se desecha el objeto db. Esto significa que no puede devolver la consulta desde el alcance de la conexión: primero debe recuperar sus datos o posponer la eliminación de la conexión hasta que no obtenga todos los datos requeridos.

La excepción que observó se debió a un error en linq2db anterior a 1.8.0 donde permitió la ejecución de consultas en la conexión eliminada, lo que condujo a una pérdida de conexión. Consulte https://github.com/linq2db/linq2db/issues/445 para obtener más información. detalles. Después de esa corrección, no puede escribir código como GetA() en su ejemplo, ya que obtendrá ObjectDisposedException cuando intente enumerar los resultados.

1
DLuk 18 nov. 2018 a las 16:11

Después de la primera llamada: en esta llamada, la conexión se abrió al usar el alcance, sin obtener datos al final del uso del alcance Cerrado.

var aItems = GetA();

Pero en esta línea:

if (!aItems.Any())

No hay ninguna conexión abierta

0
Saman Hajizade 27 dic. 2016 a las 11:29