2

Я использую QueryMultiple, который возвращает GridReader.Reader.IsConsumed является ложным, но объект был удален

Поскольку я не знаю, сколько данных я буду читать, я зацикливание над читателем с условием остановки IsConsumed:

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

Однако, я всегда получаю ObjectDisposedException на последнее прочитано. Значение IsConsumed по-прежнему false.

Я попытался передать DynamicParameters запросу с целью получить обратный вызов (который, кажется, полезен через IParameterCallbacks), но я не мог его исправить.

Я бы предпочел не иметь такого ожидаемого исключения в коде. Спасибо за любую помощь.

Я использую SQL Server, мой провайдер в .NET 4.5 System.Data.SqlClient, Щеголеватый версия 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 [email protected] 

    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. 
+0

Re редактирования: Я создал тестовую вышку с .NET 4.5, Щеголеватый 1.40.0, 'SqlClient', и все это отлично работает *. http://pastie.org/10733819 - Я рад попробовать и помогу - и если есть ошибка: исправьте это. Но я не могу воспроизвести эту проблему. Можете ли вы помочь мне привести пример, который ломается в том, как вы описываете? –

+0

Можете ли вы попробовать автономный тест, такой как Marc, в той же конфигурации и тесте, мне интересно использовать один и тот же объект соединения в нескольких контекстах, таких как параллельная задача, где вы получаете ссылку на тот же GridReader и один из них читаете и закрываете, таким образом, потребляете и другие метания исключение объекта –

+0

Я добавил неудачный модульный тест. Мне не удалось воспроизвести «ObjectDisposedException» с достаточно простым тестом, но я получил довольно близко. Я знаю, что тест все еще сложный, но я не понимаю, почему он не должен работать. – Mugen

ответ

0

Ну, похоже, проблема с реализацией 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

3

Я толкнул следующее, который проходит на 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/и т.д. вы используете (SQL Server Oracle Postgresql ...??)
  • поставщика, что ADO.NET вы используете
  • какой среды выполнения (.NET what.what? Core-clr?)/OS вы используете
  • какая точная версия библиотеки вы используете (выше, чем исходный код, который больше всего похож на 1.50.0-beta8)
+0

Я отредактировал мой вопрос с этой информацией. – Mugen

+0

@Marc Gravell не пробовал, но как это ведет к абсолютно никакой записи для нескольких Select, в текущем тесте будет одна запись, чтобы потреблять –

+0

@MrinalKamboj хороший вопрос; Я поменяю тест позже, чтобы сделать 0, 1, 2, 3, ... и т. Д. Выбирает –

1

Я сталкиваюсь с тем же вопросом с Даппером, и я - я версии 1.42.0 и SQL Server 2012 в качестве задней части. После отладки я обнаружил, что эта проблема происходит только тогда, когда мы пытаемся создать несколько объектов, используя параметр splitOn Dapper в последнем наборе результатов.

Я представил новый выпуск на GitHub https://github.com/StackExchange/dapper-dot-net/issues/469

+0

Я вижу, что это лучше подходит для комментариев, поскольку это явно не решение проблемы. Добро пожаловать в СО, так или иначе! – phaberest

+0

Я понял это, но ссылка «добавить комментарий» отключена, и я не мог добавить ее в качестве комментария. На самом деле он говорит: «У вас должно быть 50 репутации для комментариев» – sash

+0

Ну, я понимаю. SO политики ... – phaberest

0

Мой первоначальный анализ указывают на то, какое-то несоответствие между использованием базы данных cursor и GridReader, как и в случае GridReader, было бы внутренне перечислить через нужный результат в генерировать IEnumerable<T>, вы можете попробовать следующее:

  • Удалить щеголеватый с картинки, попробуйте один и тот же материал, используя .Net Data Reader, MARS и посмотреть, если он работает, как ожидалось.

  • Вы можете даже, возможно, изменить свой запрос, используя IN положение следующим образом:

    SELECT DISTINCT 
        DataDate AS Date1, 
        DataDate AS Date2 
        FROM Data_Table 
        WHERE DataDate IN (SELECT DISTINCT DataDate FROM Data_Table) 
    

Теперь здесь вы можете легко работать, используя Query<T> вместо QueryMultiple<T>, насколько я помню, запрос множественным Безразлично» t работать с Oracle, не уверен, что причиной является курсор, так как там открыто курсор для выбора в PL SQL

+0

Это не будет работать в моем случае. Пример, который я дал, был упрощен. На самом деле мне нужен QueryMultiple, поскольку мне нужно несколько и неограниченное количество отдельных вариантов. – Mugen

+0

Еще вы можете попробовать SqlDataReader и проверить, работает ли он, полностью удалить Dapper, использовать чистый ADO.Net, также вы можете удалить курсор и использовать простой Select with Query Multiple. Ваше исключение изменилось с ObjectDisposed на Null reference, правильно? –