Reader.IsConsumed 为假,但对象已被处置
Reader.IsConsumed is false but object was disposed
我正在使用 QueryMultiple
其中 returns 一个 GridReader。
因为我不知道我要读取多少数据,所以我在 reader 上循环,停止条件为 IsConsumed
:
using (var reader = conn.QueryMultiple(mySql)) {
while(!reader.IsConsumed) {
reader.Read<...>
}
}
但是,我总是在最后一次阅读时得到 ObjectDisposedException
。 IsConsumed
的值仍然是 false
.
我试图将 DynamicParameters
传递给查询以获取回调(这似乎通过 IParameterCallbacks
很有用),但我无法将其修补在一起。
我真的不想在代码中出现这样的预期异常。感谢您的帮助。
我正在使用 SQL 服务器,我的提供商是 System.Data.SqlClient
in .NET 4.5,Dapper 版本 1.40.0.0
例如一个失败的测试:
[TestMethod]
public void QueryMultipleWithCursor()
{
const string sql = @"
DECLARE @CurrentDate DATE
DECLARE DatesCursor CURSOR LOCAL FOR
SELECT DISTINCT DataDate FROM Data_Table ORDER BY DataDate
OPEN DatesCursor
FETCH NEXT FROM DatesCursor INTO @CurrentDate
WHILE @@FETCH_STATUS = 0 BEGIN
SELECT DISTINCT
DataDate AS Date1,
DataDate AS Date2
FROM Data_Table
WHERE DataDate=@CurrentDate
FETCH NEXT FROM DatesCursor INTO @CurrentDate
END
CLOSE DatesCursor
DEALLOCATE DatesCursor";
using (var conn = _database.GetConnection())
{
var reader = conn.QueryMultiple(sql);
while (!reader.IsConsumed)
{
reader.Read<DateTime, DateTime, DateTime>(
(date1, date2) => date1,
splitOn: "Date2").ToList();
}
}
}
我得到一个 NullReferenceException
具有以下堆栈:
at Dapper.SqlMapper.GridReader.NextResult() in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 4440
at Dapper.SqlMapper.GridReader.<MultiReadInternal>d__9`8.System.IDisposable.Dispose()
at Dapper.SqlMapper.GridReader.<MultiReadInternal>d__9`8.MoveNext() in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 4309
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Dapper.SqlMapper.GridReader.Read[TFirst,TSecond,TReturn](Func`3 func, String splitOn, Boolean buffered) in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 4330
at Project.MyTests.QueryMultipleWithCursor() in C:\Project\MyTests.cs:line 171
Result Message:
Test method Project.MyTests.QueryMultipleWithCursor threw exception:
System.NullReferenceException: Object reference not set to an instance of an object.
我推送了以下内容,它在 SQL 服务器 / SqlConnection
上传递;所以它可以工作:
[Fact]
public void SO35554284_QueryMultipleUntilConsumed()
{
using (var reader = connection.QueryMultiple(
"select 1 as Id; select 2 as Id; select 3 as Id;"))
{
List<HazNameId> items = new List<HazNameId>();
while (!reader.IsConsumed)
{
items.AddRange(reader.Read<HazNameId>());
}
items.Count.IsEqualTo(3);
items[0].Id.IsEqualTo(1);
items[1].Id.IsEqualTo(2);
items[2].Id.IsEqualTo(3);
}
}
我想知道这里的问题是否是特定 ADO.NET 提供商的问题。您可能想要准确指定:
- 您正在使用什么后端 RDBMS/等(SQL 服务器?Oracle?Postgresql?...?)
- 您使用的 ADO.NET 供应商
- 您使用的是什么运行时(.NET what.what?core-clr?)/OS
- 您使用的确切库版本(以上是针对源代码的,与 1.50.0-beta8 最相似)
我 运行 遇到与 Dapper 相同的问题,我使用版本 1.42.0 和 SQL Server 2012 作为后端。调试后我发现只有当我们尝试在最后一个结果集上使用 Dapper 的 splitOn 选项创建多个对象时才会发生此问题。
我已经在 GitHub 上提交了一个新问题
https://github.com/StackExchange/dapper-dot-net/issues/469
嗯,这似乎是 Dapper 实现的问题,同时我同时使用 Dapper
和 SqlDataReader
,后者更可靠:
public static SqlMapper.GridReader QueryMultipleStoredProcedure(this IDbConnection dbConnection, string spName, object parameters, out SqlDataReader sqlDataReader)
{
var gridReader = dbConnection.QueryMultiple(spName, new DynamicParameters(parameters), commandType: CommandType.StoredProcedure);
sqlDataReader = typeof (SqlMapper.GridReader).GetInstanceField<SqlDataReader>(gridReader, "reader");
return gridReader;
}
private static T GetInstanceField<T>(this Type type, object instance, string fieldName)
{
var bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
var field = type.GetField(fieldName, bindFlags);
return (T) field?.GetValue(instance);
}
然后我可以使用sqlDataReader.HasRows
我正在使用 QueryMultiple
其中 returns 一个 GridReader。
因为我不知道我要读取多少数据,所以我在 reader 上循环,停止条件为 IsConsumed
:
using (var reader = conn.QueryMultiple(mySql)) {
while(!reader.IsConsumed) {
reader.Read<...>
}
}
但是,我总是在最后一次阅读时得到 ObjectDisposedException
。 IsConsumed
的值仍然是 false
.
我试图将 DynamicParameters
传递给查询以获取回调(这似乎通过 IParameterCallbacks
很有用),但我无法将其修补在一起。
我真的不想在代码中出现这样的预期异常。感谢您的帮助。
我正在使用 SQL 服务器,我的提供商是 System.Data.SqlClient
in .NET 4.5,Dapper 版本 1.40.0.0
例如一个失败的测试:
[TestMethod]
public void QueryMultipleWithCursor()
{
const string sql = @"
DECLARE @CurrentDate DATE
DECLARE DatesCursor CURSOR LOCAL FOR
SELECT DISTINCT DataDate FROM Data_Table ORDER BY DataDate
OPEN DatesCursor
FETCH NEXT FROM DatesCursor INTO @CurrentDate
WHILE @@FETCH_STATUS = 0 BEGIN
SELECT DISTINCT
DataDate AS Date1,
DataDate AS Date2
FROM Data_Table
WHERE DataDate=@CurrentDate
FETCH NEXT FROM DatesCursor INTO @CurrentDate
END
CLOSE DatesCursor
DEALLOCATE DatesCursor";
using (var conn = _database.GetConnection())
{
var reader = conn.QueryMultiple(sql);
while (!reader.IsConsumed)
{
reader.Read<DateTime, DateTime, DateTime>(
(date1, date2) => date1,
splitOn: "Date2").ToList();
}
}
}
我得到一个 NullReferenceException
具有以下堆栈:
at Dapper.SqlMapper.GridReader.NextResult() in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 4440
at Dapper.SqlMapper.GridReader.<MultiReadInternal>d__9`8.System.IDisposable.Dispose()
at Dapper.SqlMapper.GridReader.<MultiReadInternal>d__9`8.MoveNext() in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 4309
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Dapper.SqlMapper.GridReader.Read[TFirst,TSecond,TReturn](Func`3 func, String splitOn, Boolean buffered) in D:\Dev\dapper-dot-net\Dapper NET40\SqlMapper.cs:line 4330
at Project.MyTests.QueryMultipleWithCursor() in C:\Project\MyTests.cs:line 171
Result Message:
Test method Project.MyTests.QueryMultipleWithCursor threw exception:
System.NullReferenceException: Object reference not set to an instance of an object.
我推送了以下内容,它在 SQL 服务器 / SqlConnection
上传递;所以它可以工作:
[Fact]
public void SO35554284_QueryMultipleUntilConsumed()
{
using (var reader = connection.QueryMultiple(
"select 1 as Id; select 2 as Id; select 3 as Id;"))
{
List<HazNameId> items = new List<HazNameId>();
while (!reader.IsConsumed)
{
items.AddRange(reader.Read<HazNameId>());
}
items.Count.IsEqualTo(3);
items[0].Id.IsEqualTo(1);
items[1].Id.IsEqualTo(2);
items[2].Id.IsEqualTo(3);
}
}
我想知道这里的问题是否是特定 ADO.NET 提供商的问题。您可能想要准确指定:
- 您正在使用什么后端 RDBMS/等(SQL 服务器?Oracle?Postgresql?...?)
- 您使用的 ADO.NET 供应商
- 您使用的是什么运行时(.NET what.what?core-clr?)/OS
- 您使用的确切库版本(以上是针对源代码的,与 1.50.0-beta8 最相似)
我 运行 遇到与 Dapper 相同的问题,我使用版本 1.42.0 和 SQL Server 2012 作为后端。调试后我发现只有当我们尝试在最后一个结果集上使用 Dapper 的 splitOn 选项创建多个对象时才会发生此问题。
我已经在 GitHub 上提交了一个新问题 https://github.com/StackExchange/dapper-dot-net/issues/469
嗯,这似乎是 Dapper 实现的问题,同时我同时使用 Dapper
和 SqlDataReader
,后者更可靠:
public static SqlMapper.GridReader QueryMultipleStoredProcedure(this IDbConnection dbConnection, string spName, object parameters, out SqlDataReader sqlDataReader)
{
var gridReader = dbConnection.QueryMultiple(spName, new DynamicParameters(parameters), commandType: CommandType.StoredProcedure);
sqlDataReader = typeof (SqlMapper.GridReader).GetInstanceField<SqlDataReader>(gridReader, "reader");
return gridReader;
}
private static T GetInstanceField<T>(this Type type, object instance, string fieldName)
{
var bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
var field = type.GetField(fieldName, bindFlags);
return (T) field?.GetValue(instance);
}
然后我可以使用sqlDataReader.HasRows