Reader.IsConsumed는 거짓이지만 객체는 폐기되었습니다.

dapper idisposable objectdisposedexception sqldatareader

문제

QueryMultiple 를 반환하는 QueryMultiple을 사용하고 있습니다.

내가 얼마나 많은 양의 데이터를 읽어야할지 모르겠으므로 독자들에게 IsConsumed 의 정지 조건을 IsConsumed .

using (var reader = conn.QueryMultiple(mySql)) {
  while(!reader.IsConsumed) {
    reader.Read<...>
  }
}

그러나, 나는 항상 마지막 읽을 때 ObjectDisposedException 을 얻고있다. IsConsumed 의 값은 여전히 false 입니다.

DynamicParameters 를 콜백 ( IParameterCallbacks 를 통해 유용함)을 얻으려는 의도로 쿼리에 전달하려고 시도했지만 함께 패치 할 수는 없었습니다.

코드에서 예상되는 예외를 정말로 갖고 싶지 않습니다. 어떤 도움을 주셔서 감사합니다.

SQL Server를 사용하고 있습니다. 공급자는 .NET 4.5, Dapper 버전 1.40.0.0의 System.Data.SqlClient 입니다.

실패한 테스트 예 :

        [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.

수락 된 답변

DapperSqlDataReader 를 모두 사용하고있는 Dapper 구현의 문제 인 것 같습니다.

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 를 사용할 수 있습니다 sqlDataReader.HasRows


전문가 답변

SQL Server / 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 / etc를 사용하고 있습니까 (SQL Server? Oracle? Postgresql? ...?)
  • 사용중인 ADO.NET 공급자
  • 어떤 런타임 (.NET what.what? core-clr?) / OS
  • 정확한 라이브러리 버전은 무엇입니까 (위의 내용은 1.50.0-beta8과 가장 유사한 소스 코드에 대한 것입니다)


아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.