sql >> Base de Datos >  >> RDS >> Mysql

Ya hay un DataReader abierto... aunque no lo esté

Sospecho que este es el problema, al final del método:

this.connectionPool.Putback(sqlConnection);

Solo estás tomando dos elementos del iterador, por lo que nunca completa el while bucle a menos que en realidad solo haya un valor devuelto por el lector. Ahora está usando LINQ, que llamará automáticamente a Dispose() en el iterador, entonces using la declaración aún se deshará del lector, pero no volverá a colocar la conexión en el grupo. Si haces eso en un finally block, creo que estarás bien:

var sqlConnection = this.connectionPool.Take();
try
{
    // Other stuff here...

    using (var reader = this.selectWithSourceVectorCommand.ExecuteReader())
    {
        while (reader.Read())
        {
            yield return ReaderToVectorTransition(reader);
        }
    }
}
finally
{
    this.connectionPool.Putback(sqlConnection);
}

O idealmente, si su grupo de conexiones es su propia implementación, haga Take devuelve algo que implementa IDisposable y devuelve la conexión al grupo cuando termina.

Aquí hay un programa corto pero completo para demostrar lo que está pasando, sin ninguna base de datos real involucrada:

using System;
using System.Collections.Generic;
using System.Linq;

class DummyReader : IDisposable
{
    private readonly int limit;
    private int count = -1;
    public int Count { get { return count; } }

    public DummyReader(int limit)
    {
        this.limit = limit;
    }

    public bool Read()
    {
        count++;
        return count < limit;
    }

    public void Dispose()
    {
        Console.WriteLine("DummyReader.Dispose()");
    }
}

class Test
{    
    static IEnumerable<int> FindValues(int valuesInReader)
    {
        Console.WriteLine("Take from the pool");

        using (var reader = new DummyReader(valuesInReader))
        {
            while (reader.Read())
            {
                yield return reader.Count;
            }
        }
        Console.WriteLine("Put back in the pool");
    }

    static void Main()
    {
        var data = FindValues(2).Take(2).ToArray();
        Console.WriteLine(string.Join(",", data));
    }
}

Tal como está escrito, modelando la situación con el lector solo encontrando dos valores, el resultado es:

Take from the pool
DummyReader.Dispose()
0,1

Tenga en cuenta que el lector se desecha, pero nunca llegamos a devolver nada de la piscina. Si cambia Main para modelar la situación en la que el lector solo tiene un valor, así:

var data = FindValues(1).Take(2).ToArray();

Luego recorremos todo el while bucle, por lo que la salida cambia:

Take from the pool
DummyReader.Dispose()
Put back in the pool
0

Le sugiero que copie mi programa y experimente con él. Asegúrese de entender todo acerca de lo que está pasando... luego podrá aplicarlo a su propio código. Es posible que desee leer mi artículo sobre detalles de implementación del bloque iterador también.