首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET DataTable 與 DataSet 互轉完整指南:新增、移除、複製、關聯與效能考量

     編輯:ASP.NET 基礎

核心關係:DataSet = DataTable 集合 + 關聯 + 約束

  • DataTable:單一記憶體資料表 (Rows, Columns, Constraints)。
  • DataSet:多 DataTable 容器,支援 **DataRelation** (父子關聯)、**UniqueConstraint/ForeignKeyConstraint**。
  • **效能**:單表操作用 `DataTable` 較輕量;多表關聯查詢、離線編輯、XML 序列化用 `DataSet`。

基本互轉操作

1. DataTable → DataSet (加入)


DataTable dt = GetCustomers(); // 既有 DataTable
DataSet ds = new DataSet();
ds.Tables.Add(dt); // dt 現在屬於 ds,Tables["Customers"] 可存取

// 或指定表名
dt.TableName = "Customers";
ds.Tables.Add(dt);

2. DataSet → DataTable (取出)


DataSet ds = GetDataSet();

// 依索引
DataTable dt1 = ds.Tables[0];

// 依表名 (推薦)
DataTable dt2 = ds.Tables["Customers"]; // 找不到回傳 null

// 安全檢查
if (ds.Tables.Contains("Orders"))
    DataTable dt3 = ds.Tables["Orders"];

3. 複製 DataTable 到新 DataSet (不影響來源)


// Clone 只複製結構 (Schema),不複製資料
DataSet dsClone = ds.Clone(); 

// Copy 複製結構 + 資料
DataSet dsCopy = ds.Copy();

// 單表複製
DataTable dtCopy = dt.Copy();       // 結構 + 資料
DataTable dtClone = dt.Clone();     // 僅結構

4. 移除 DataTable


ds.Tables.Remove("OldTable");        // 依名稱
ds.Tables.RemoveAt(0);               // 依索引
ds.Tables.Remove(dt);                // 依物件參考

進階:DataRelation 建立主從關聯


DataSet ds = new DataSet();
DataTable dtParent = ds.Tables.Add("Categories");
DataTable dtChild = ds.Tables.Add("Products");

// 定義欄位
dtParent.Columns.Add("CategoryId", typeof(int));
dtParent.Columns.Add("CategoryName", typeof(string));
dtChild.Columns.Add("ProductId", typeof(int));
dtChild.Columns.Add("CategoryId", typeof(int));
dtChild.Columns.Add("ProductName", typeof(string));

// 設定主鍵
dtParent.PrimaryKey = new[] { dtParent.Columns["CategoryId"] };

// 建立關聯
DataRelation rel = new DataRelation("Category_Products",
    dtParent.Columns["CategoryId"],  // 父欄位
    dtChild.Columns["CategoryId"]);  // 子欄位
ds.Relations.Add(rel);

// 現在可導航
foreach (DataRow parent in dtParent.Rows)
{
    DataRow[] children = parent.GetChildRows(rel); // 取得子列
    Console.WriteLine($"{parent["CategoryName"]} 有 {children.Length} 個產品");
}

實用擴充方法


public static class DataSetExtensions
{
    /// 將多個 DataTable 合併為單一 DataSet
    public static DataSet ToDataSet(this IEnumerable tables, string dataSetName = "Merged")
    {
        var ds = new DataSet(dataSetName);
        foreach (var dt in tables)
            ds.Tables.Add(dt.Copy()); // 複製避免跨 DataSet 共用
        return ds;
    }

    /// DataSet 序列化為 XML (含 Schema)
    public static string ToXml(this DataSet ds, bool writeSchema = true)
    {
        using (var sw = new StringWriter())
        {
            ds.WriteXml(sw, writeSchema ? XmlWriteMode.WriteSchema : XmlWriteMode.IgnoreSchema);
            return sw.ToString();
        }
    }

    /// 從 XML 還原 DataSet
    public static DataSet FromXml(string xml)
    {
        var ds = new DataSet();
        using (var sr = new StringReader(xml))
            ds.ReadXml(sr);
        return ds;
    }
}

效能與記憶體考量

常見錯誤

  1. 跨 DataSet 直接 Add 同一 DataTable 實例:會拋 `This table already belongs to another DataSet`。解決:用 `dt.Copy()` 或 `ds.Tables.Add(dt.Copy())`。
  2. Tables["Name"] 回傳 null 卻直接用:一定要 `Contains` 或 `?.` 檢查。
  3. PrimaryKey 未設定就建立 DataRelation**:父表必須有 PrimaryKey,否則關聯無效。
  4. 修改 Clone() 出來的空 DataTable 結構**:會影響原 DataSet (Clone 共用 Column 集合參考)。改用 `dt.Copy().Clone()` 完全隔離。

總結

DataTable ↔ DataSet 互轉核心 API:
• `Tables.Add/Remove/Contains` 管理集合
• `Copy/Clone/ImportRow` 控制複製深度
• `DataRelation` 建立關聯導航
• `ReadXml/WriteXml` 序列化持久化
單表場景**優先用 DataTable** 降低記憶體;多表關聯、離線編輯、XML 匯出入才用 DataSet。理解 `Copy` (深層) vs `Clone` (淺層結構) 差異,是避免記憶體洩漏與資料汙染的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
操作記憶體影響建議
ds.Copy()完整複製所有資料,記憶體翻倍大量資料避免使用,改用 Clone + ImportRow
dt.ImportRow(row)逐列複製,可篩選大量資料分頁複製
ds.ReadXml/WriteXml完整序列化大資料改用 SqlBulkCopy / 二進制格式
DataRelation建立索引,增加記憶體僅在需要導航/約束時建立