2014-03-19 60 views
1

我用一個參數調用這個方法來調用存儲過程,我正在使用它來查看yield是否對我的團隊有好處。使用SqlDbReader方法產生給出在讀取器關閉時調用CheckDataIsReady的嘗試無效。異常

這是調用存儲過程的通用方法。它調用工作正常,

var parameters = new List<SqlParameter>(); 
parameters.Add(CreateParamter("GL45", "@prefix", SqlDbType.VarChar)); 
var reader = StoreProcedureReader("Yield", parameters.ToArray()); 

這將返回我需要的讀者,但下一行

string value = reader.First()[0].ToString(); 

導致錯誤時拋出,無效試圖調用CheckDataIsReady時讀取器已關閉。

public static IEnumerable<IDataRecord> StoreProcedureReader(String StoredProcedureName, SqlParameter[] paramters) 
    { 
     using (var conn = new SqlConnection(MyConnectionString)) 
     { 
      using (var cmd = new SqlCommand(StoredProcedureName, conn)) 
      { 
       cmd.CommandType = CommandType.StoredProcedure; 
       cmd.Parameters.AddRange(paramters); 
       conn.Open(); 
       using (var reader = cmd.ExecuteReader()) 
       { 
        while (reader.Read()) 
        { 
         yield return reader; 
        }       
       } 
      } 
     } 
    } 

我已經在這裏看到在計算器上幾樣,似乎我可能錯過了一些東西,其中一個例子using語句有SqlCommand的後結束,我試過了,但把它退了出去。我可以合作關閉一個我回來的東西。

+0

你得到第一個閱讀器=>就該功能而言完成的工作=>停止循環,退出 –

回答

1

我認爲這個問題是由於使用了yield return。一旦統計員被處理後,您的讀者將被處置,在.First()的電話回覆之前發生。

因此,當您在得到的IDataRecord上使用索引器[0]時,它會拋出異常,因爲返回的IDataRecord(即SqlDataReader)已被丟棄。

你最好的選擇可能是填充和複製出來自讀取器的結果和產生的是,這將確保讀者配置結果前被檢索,即

public static IEnumerable<IList<object>> StoreProcedureReader(String StoredProcedureName, SqlParameter[] paramters) 
{ 
    using (var conn = new SqlConnection(MyConnectionString)) 
    { 
     using (var cmd = new SqlCommand(StoredProcedureName, conn)) 
     { 
      cmd.CommandType = CommandType.StoredProcedure; 
      cmd.Parameters.AddRange(paramters); 
      conn.Open(); 
      using (var reader = cmd.ExecuteReader()) 
      { 
       while (reader.Read()) 
       { 
        var fieldCount = reader.FieldCount; 
        var results = new object[fieldCount]; 
        for(var i = 0; i < fieldCount; ++i) 
        { 
         results[i] = reader[i]; 
        } 
        yield return results; 
       }       
      } 
     } 
    } 
} 

通知IEnumerable<IList<object>>返回類型,你的調用代碼不需要改變。

這確實有所有數據被讀入內存的缺點。這將避免這種情況的另一種方法是手動控制導致IEnumerator<T>,所以你的原代碼,請執行下列操作:

using(var enumerator = reader.GetEnumerator()) 
{ 
    // Move to first 
    if(!enumerator.MoveNext()) 
     throw new NotImplementedException(); 
    var value = enumerator.Current[0].ToString(); 
} 

這將確保結果IEnumerator<T>沒有設置,直到您已經閱讀你感興趣的值

+0

好的解釋,好吧,那麼我將如何去獲取集合中的第一個項目?我想我會看到的是集合中的第一個數據庫行,就是這樣。由於First是IEnumerable的一種方法。但它似乎正在試圖迴歸收益率。 –

+0

'First'不是'IEnumerable '的一種方法,它是一種擴展方法。 'yield'關鍵字是延遲執行的實現,這意味着只有當您試圖枚舉所產生的'IEnumerable '時,方法的內容纔會被執行。 – Lukazoid

相關問題