Кажется, есть некоторые проблемы с библиотекой MySQL .NET. Несколько дней назад они исправили некоторые из этих проблем с 6.2.2, связанные с освобождением соединений.
Но есть и проблема с SubSonic. Я использовал шаблоны LINQ с MySQL для генерации своих классов. Всякий раз, когда FirstOrDefault () или First () (другие похожие функции, вероятно, имеют ту же проблему).
Для запроса, такого как:
var db = new MyDb("CONNECTIONSTRING_NAME");
var userExt = (from pe in db.PhoneExtensions
where
pe.FirstName.ToLower() == firstName.ToLower() &&
pe.LastName.ToLower() == lastName.ToLower()
select pe.Extension).FirstOrDefault();
Это приведет к выполнению запроса, и читатель будет не удален.
Проблема в Linq.Structure.DbQueryProvider в методе Project of T.
while (reader.Read())
{
yield return fnProjector(reader);
}
reader.Dispose();
Dispose () никогда не вызывается при использовании FirstOrDefault () и других подобных методов.
Простое исправление:
try
{
while (reader.Read())
{
yield return fnProjector(reader);
}
}
finally
{
reader.Dispose();
}
Простой быстрый тест, показывающий проблему:
private class DbDataReader : System.IDisposable
{
#region IDisposable Members
public void Dispose() { }
#endregion
}
private class DbQueryProvider
{
private DbDataReader _reader;
public bool IsReaderDisposed { get { return _reader == null; } }
public DbQueryProvider()
{
_reader = new DbDataReader();
}
public IEnumerable<int> Project(int numResults)
{
int i = 0;
while (i < numResults)
{
yield return i++;
}
_reader.Dispose();
_reader = null;
}
public IEnumerable<int> ProjectWithFinally(int numResults)
{
int i = 0;
try
{
while (i < numResults)
{
yield return i++;
}
}
finally
{
_reader.Dispose();
_reader = null;
}
}
}
[Test]
public void YieldReturn_Returns_TrueForIsReaderDisposed()
{
const int numResults = 1;
var qp1 = new DbQueryProvider();
var q1 = qp1.Project(numResults);
Assert.IsInstanceOf(typeof(int), q1.First());
var qp2 = new DbQueryProvider();
var q2 = qp2.Project(numResults);
Assert.IsInstanceOf(typeof(int), q2.FirstOrDefault());
var qp3 = new DbQueryProvider();
var q3 = qp3.Project(numResults);
Assert.IsInstanceOf(typeof(int), q3.Single());
var qp4 = new DbQueryProvider();
var q4 = qp4.Project(numResults);
Assert.IsInstanceOf(typeof(int), q4.SingleOrDefault());
Assert.IsTrue(qp1.IsReaderDisposed);
Assert.IsTrue(qp2.IsReaderDisposed);
Assert.IsTrue(qp3.IsReaderDisposed);
Assert.IsTrue(qp4.IsReaderDisposed);
}
[Test]
public void YieldReturnFinally_Returns_TrueForIsReaderDisposed()
{
const int numResults = 1;
var qp1 = new DbQueryProvider();
var q1 = qp1.ProjectWithFinally(numResults);
Assert.IsInstanceOf(typeof(int), q1.First());
var qp2 = new DbQueryProvider();
var q2 = qp2.ProjectWithFinally(numResults);
Assert.IsInstanceOf(typeof(int), q2.FirstOrDefault());
var qp3 = new DbQueryProvider();
var q3 = qp3.ProjectWithFinally(numResults);
Assert.IsInstanceOf(typeof(int), q3.Single());
var qp4 = new DbQueryProvider();
var q4 = qp4.ProjectWithFinally(numResults);
Assert.IsInstanceOf(typeof(int), q4.SingleOrDefault());
Assert.IsTrue(qp1.IsReaderDisposed);
Assert.IsTrue(qp2.IsReaderDisposed);
Assert.IsTrue(qp3.IsReaderDisposed);
Assert.IsTrue(qp4.IsReaderDisposed);
}
YieldReturnFinally_Returns_TrueForIsReaderDisposed проходит, но YieldReturn_Returns_TrueForIsReaderDisposed завершается ошибкой.
Я проверил это на проекте, над которым я работаю, который скоро будет в производстве, и, похоже, это работает без проблем. Протестировано с максимальным размером пула соединений 5 и не имело проблем с пулом соединений (никогда не заканчивались соединения на моем компьютере разработчика при выполнении 1 запроса за раз).
Я также обнаружил некоторые проблемы в Extensions.Database, связанные с изменением типов и назначений.
Я разработал проект на github, внес изменения и сделал запрос на извлечение информации, надеюсь, он попадет к нужным людям.