Eu suspeito que este é o problema, no final do método:
this.connectionPool.Putback(sqlConnection);
Você está apenas tomando dois elementos do iterador - para que você nunca complete o
while
loop, a menos que haja apenas um valor retornado do leitor. Agora você está usando o LINQ, que chamará automaticamente Dispose()
no iterador, então seu using
ainda estará descartando o leitor - mas você não está colocando a conexão de volta no pool. Se você fizer isso em um finally
bloco, eu acho que você vai ficar bem: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);
}
Ou, idealmente, se seu pool de conexões for sua própria implementação, faça
Take
retorna algo que implementa IDisposable
e retorna a conexão de volta ao pool quando terminar. Aqui está um programa curto, mas completo, para demonstrar o que está acontecendo, sem nenhum banco de dados real envolvido:
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));
}
}
Conforme escrito - modelando a situação com o leitor encontrando apenas dois valores - a saída é:
Take from the pool
DummyReader.Dispose()
0,1
Observe que o leitor está disposto, mas nunca chegamos a devolver nada do pool. Se você alterar
Main
para modelar a situação onde o leitor tem apenas um valor, assim:var data = FindValues(1).Take(2).ToArray();
Em seguida, percorremos todo o caminho
while
loop, então a saída muda:Take from the pool
DummyReader.Dispose()
Put back in the pool
0
Eu sugiro que você copie meu programa e experimente com ele. Certifique-se de entender tudo sobre o que está acontecendo... então você pode aplicá-lo ao seu próprio código. Você pode querer ler meu artigo sobre detalhes da implementação do bloco do iterador também.