sql >> Database >  >> RDS >> Mysql

Er is al een open DataReader ... ook al is dat niet het geval

Ik vermoed dat dit het probleem is, aan het einde van de methode:

this.connectionPool.Putback(sqlConnection);

Je neemt alleen twee elementen uit de iterator - dus je voltooit nooit de while lus tenzij er eigenlijk maar één waarde wordt geretourneerd door de lezer. Nu gebruik je LINQ, dat automatisch Dispose() . aanroept op de iterator, dus uw using statement zal nog steeds de lezer weggooien - maar je zet de verbinding niet terug in de pool. Als je dat doet in een finally blok, ik denk dat het wel goed komt:

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);
}

Of idealiter, als uw verbindingspool uw eigen implementatie is, maakt u Take iets teruggeven dat IDisposable implementeert en stuurt de verbinding terug naar de pool als het klaar is.

Hier is een kort maar compleet programma om te demonstreren wat er aan de hand is, zonder dat er daadwerkelijke databases bij betrokken zijn:

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));
    }
}

Zoals geschreven - modellering van de situatie waarbij de lezer slechts twee waarden vindt - is de uitvoer:

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

Merk op dat de lezer is weggegooid, maar we komen nooit zo ver als iets teruggeven uit het zwembad. Als u Main wijzigt om de situatie te modelleren waarin de lezer slechts één waarde heeft, zoals dit:

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

Dan komen we helemaal door de while loop, zodat de uitvoer verandert:

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

Ik stel voor dat je mijn programma kopieert en ermee experimenteert. Zorg ervoor dat je alles begrijpt over wat er aan de hand is... dan kun je het toepassen op je eigen code. Misschien wil je mijn artikel lezen over implementatiedetails van iteratorblok ook.



  1. Multi-Statement TVF's in Dynamics CRM

  2. hoe u alle mysql-tuple-resultaten kunt krijgen en converteren naar json

  3. EF6 MySQL StrongTypingException wanneer kolom niet PK is

  4. MySQL - Twee dingen tellen met verschillende voorwaarden