2

我使用的是QueryMultiple,它返回GridReaderReader.IsConsumed爲false,但處理對象

因爲我不知道我有多少數據我會讀,我遍歷了讀者的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

重新編輯:我建立了一個試驗檯與.NET 4.5,小巧玲瓏1.40.0,'SqlClient', *它一切正常*。 http://pastie.org/10733819 - 我很樂意嘗試和幫助 - 如果有錯誤:修復它。但我不能重現這個問題。你能幫我找到一個能夠按照你描述的方式打破的例子嗎? –

+0

你可以像Marc一樣單獨測試相同的配置和測試,我想知道在多個上下文中使用相同的連接對象,比如並行任務,在這裏你可以獲得同一個GridReader的引用,並且其中一個讀取和關閉,因此消耗和其他投擲處理異常的對象 –

+0

我添加了失敗的單元測試。我無法用一個足夠簡單的測試來重現ObjectDisposedException,但是我非常接近。我知道測試仍然複雜,但我不明白爲什麼它不應該工作。 – Mugen

回答

0

那麼這似乎是一個問題與Dapper實現,我平均時間使用既DapperSqlDataReader,這是更可靠:

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服務器Oracle PostgreSQL的...????)
  • 什麼ADO.NET提供者使用的是
  • 運行什麼(.NET what.what?核心CLR?)/ OS使用的是
  • 你使用什麼確切的庫版本(上面是對源代碼,這是最相似的1.50.0-beta8)
+0

我用這個信息編輯了我的問題。 – Mugen

+0

@Marc Gravell還沒有嘗試過,但是這對於多重選擇絕對沒有記錄,在當前的測試中會有一條記錄消耗 –

+0

@MrinalKamboj好問題;我會稍後改變測試做0,1,2,3,... etc選擇 –

1

我遇到了與Dapper相同的問題,我是我們將版本1.42.0和SQL Server 2012作爲後端。在調試時,我發現只有當我們嘗試在最後的結果集上使用Dapper的splitOn選項創建多個對象時,纔會發生此問題。

我已經提交了新的問題,在GitHub上 https://github.com/StackExchange/dapper-dot-net/issues/469

+0

我認爲這將更好地適合作爲評論,因爲它顯然不是解決問題的辦法。無論如何,歡迎來到SO! – phaberest

+0

我意識到它,但「添加評論」鏈接已禁用,我無法將其添加爲評論。其實它說,「你必須有50名評論」 – sash

+0

嗯,我明白了。所以政治...... – phaberest

0

我最初的分析表明是某種使用數據庫cursorGridReader之間的不匹配,如在GridReader情況下,它會在內部通過選擇結果枚舉產生IEnumerable<T>,你可以嘗試以下方法:

  • 從圖片刪除小巧玲瓏,使用.NET數據讀取器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>輕鬆地工作,據我記得,查詢多個沒有按」與Oracle工作,不知道是否光標是原因,因爲打開一個光標是必選的PL選擇SQL

+0

這不適用於我的情況。我給的例子被簡化了。實際上,我需要QueryMultiple,因爲我需要多個不限數量的單獨選擇。 – Mugen

+0

你還可以嘗試SqlDataReader並檢查它是否工作,完全刪除Dapper,使用純ADO.Net,也可以刪除光標並使用簡單的Select with Query Multiple。您的異常已從ObjectDisposed更改爲空引用,對嗎? –