摘要:ADO.NET 2.0:如何排除錯誤訊息「當目前沒有資料時,嘗試讀取無效」(C#)
圖表1
圖表2
圖表 1 與 2 所示的程式示範如何取得資料命令所傳回的兩個結果集,並將這兩個結果集之所有資料記錄之所有欄位的內容顯示於表單上的 TextBox 控制項中。
本範例將兩道 SELECT 陳述式指派給 SqlCommand 物件的 CommandText 屬性,因此在使用 ExecuteReader 方法執行資料命令後會傳回兩個結果集。我們藉由呼叫 SqlDataReader 物件的 NextResult 方法來循序處理各個結果集,而在處理個別的結果集時,則呼叫 SqlDataReader 物件的 GetName 方法來取得欄位名稱(亦即 myReader.GetName(i)),並位置順序傳遞給 SqlDataReader 物件來取得欄位的資料內容(亦即 myReader[i])。
特別要說明的是,使用 Using 陳述式來執行資料命令,產生 SqlDataReader 物件,並傳回多個資料結果集之後,如果搭配 Do..While 迴圈來取得結果集所有資料記錄之各欄位的名稱與欄位的內容時,會出現「當目前沒有資料時,嘗試讀取無效」的錯誤訊息。
怎麼會發生這個問題呢?問題就出在 Do…While 迴圈身上。Do…While 迴圈的特色是,不論指定的判斷運算式之結果是 True 還是 False,至少都會將 { } 內的程式碼區塊執行一次。換句話說,在沒有執行 myReader.Read() 函式之前,如果先執行 myReader.GetName(i) 函式來取得資料,當然就會發生錯誤。
要解決這個問題,請您將原本的 Do…While 迴圈改寫為 While 迴圈,判斷式一樣可以利用 myReader.Read()。相關程式碼撰寫於表單的 Load 事件處理常式中,列示如下:
private void CH6_DemoForm010_Load(object sender, EventArgs e)
{
...
try
{
// 建立連接。
using (SqlConnection con = new
SqlConnection(connectStringBuilder.ConnectionString))
{
// 建立資料命令物件(亦即SqlCommand 物件)。
SqlCommand foxCMD = new SqlCommand();
foxCMD.Connection = con;
// 將兩道SELECT 陳述式指派給CommandText 屬性,
// 此舉將使得資料命令會傳回兩個結果集。
foxCMD.CommandText = "SELECT * FROM 章立民研究室;SELECT * FROM 客戶";
// 開啟連接。
con.Open();
int resultSetCounter = 1;
StringBuilder s = new StringBuilder();
// 執行會傳回多個結果集的資料命令。
using (SqlDataReader myReader = foxCMD.ExecuteReader())
{
bool fNextResult = true;
// 循序處理各個結果集。
do
{
...
switch (resultSetCounter)
{
case 1:
s.AppendLine("「章立民研究室」資料表的資料記錄");
break;
case 2:
s.AppendLine("「客戶」資料表的資料記錄");
break;
}
...
// 取得結果集所有資料記錄之各欄位的名稱與欄位的內容。
if (myReader.HasRows)
{
while (myReader.Read())
{
for (int i = 0; i < myReader.FieldCount; i++)
{
s.AppendLine(myReader.GetName(i) + ": " + myReader[i].ToString());
}
...
}
}
// 將資料讀取器前移到下一個結果集。
fNextResult = myReader.NextResult();
resultSetCounter += 1;
}
while (fNextResult);
// 將所取得的資料指派給TextBox 控制項的Text 屬性。
txtInfo.Text = s.ToString();
}
}
}
...
}