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();
这将导致查询被执行并且阅读器将不会被释放。
问题出在T方法的Project中的Linq.Structure.DbQueryProvider。
while (reader.Read())
{
yield return fnProjector(reader);
}
reader.Dispose();
在使用 FirstOrDefault() 和其他类似方法时,永远不会调用 Dispose()。
一个简单的修复:
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 上 fork 了这个项目,提交了我的更改并提出了拉取请求,希望能找到合适的人。