首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C# SqlDataReader 轉 DataTable:循環讀取行數據填充表的標準實現

     編輯:程式設計綜合問答

將 SqlDataReader (只進流) 轉為 DataTable (內存表),核心步驟:1. 根據 Reader 元數據建立列、2. 循環 Read() 填充行。原代碼邏輯正確,可能因調試視角導致誤以為無數據。

標準實現


public static DataTable ConvertDataReaderToDataTable(SqlDataReader reader) {
    DataTable dt = new DataTable();
    
    // 1. 建立列結構 (Schema)
    for (int i = 0; i < reader.FieldCount; i++) {
        DataColumn col = new DataColumn();
        col.ColumnName = reader.GetName(i);
        col.DataType = reader.GetFieldType(i);
        dt.Columns.Add(col);
    }
    
    // 2. 循環讀取行數據
    while (reader.Read()) {
        DataRow row = dt.NewRow();
        for (int i = 0; i < reader.FieldCount; i++) {
            // 直接賦值,DBNull.Value 會自動處理
            row[i] = reader[i]; 
        }
        dt.Rows.Add(row);
    }
    
    // 3. 關閉 Reader (調用者負責,或這裡關閉)
    // reader.Close(); 
    
    return dt;
}

優化版:SchemaTable 直接獲取列信息


public static DataTable ConvertDataReaderToDataTableOptimized(SqlDataReader reader) {
    DataTable dt = new DataTable();
    
    // 使用 GetSchemaTable 獲取完整列元數據 (含主鍵、自增、允許空等)
    DataTable schemaTable = reader.GetSchemaTable();
    foreach (DataRow schemaRow in schemaTable.Rows) {
        DataColumn col = new DataColumn();
        col.ColumnName = schemaRow["ColumnName"].ToString();
        col.DataType = (Type)schemaRow["DataType"];
        col.AllowDBNull = (bool)schemaRow["AllowDBNull"];
        col.Unique = (bool)schemaRow["IsUnique"];
        col.AutoIncrement = (bool)schemaRow["IsAutoIncrement"];
        // 可複製更多屬性...
        dt.Columns.Add(col);
    }
    
    // 填充數據
    while (reader.Read()) {
        DataRow row = dt.NewRow();
        for (int i = 0; i < reader.FieldCount; i++) {
            row[i] = reader[i];
        }
        dt.Rows.Add(row);
    }
    
    return dt;
}

一行代碼方案:DataTable.Load (內部實現相同)


// 最簡潔,內部自動處理 Schema 和數據填充
DataTable dt = new DataTable();
dt.Load(reader); // 自動關閉 reader
return dt;

常見問題排查

現象可能原因排查
Rows.Count = 0Reader 已讀完 (Read() 返回 false)確保傳入的 Reader 尚未 Read,或調用前未遍歷
Columns 為空FieldCount = 0 (SQL 無結果集)檢查 SQL 執行是否返回結果 (SELECT vs INSERT/UPDATE)
數據類型不匹配GetFieldType 返回 Provider 特定類型用 reader.GetProviderSpecificFieldType(i) 或統一轉 String
大數據量 OOMDataTable 全量載入內存分頁查詢、流式處理、或用 Dapper 映射實體流

現代替代:Dapper 直接映射實體列表


// 依賴: Dapper
using (var conn = new SqlConnection(connStr)) {
    conn.Open();
    using (var reader = cmd.ExecuteReader()) {
        // 直接映射到強類型列表,無 DataTable 開銷
        var list = reader.Parse().AsList(); // Dapper 拓展方法
        // 或手寫映射
        var users = new List();
        while (reader.Read()) {
            users.Add(new User {
                Id = reader.GetInt32(0),
                Name = reader.GetString(1),
                Email = reader.IsDBNull(2) ? null : reader.GetString(2)
            });
        }
    }
}

最佳實踐建議

  1. 優先用 DataTable.Load(reader):簡潔、官方實現、自動關閉 Reader。
  2. 2. 大數據集勿用 DataTable:內存壓力大,改用流式映射實體 (Dapper/手寫)。 3. Reader 所有權清晰:誰創建誰關閉,或用 using 確保釋放。 4. DBNull 處理:reader.IsDBNull(i) ? null : reader.GetValue(i)。 5. 異步讀取:await reader.ReadAsync()、dt.LoadAsync(reader) (Core 3.0+)。

DataReader → DataTable 是 ADO.NET 經典轉換,理解其「Schema 建立 → 數據填充」兩階段,能靈活應對各種數據源轉換場景。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved