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

DataTable.Clone() vs Copy() 深度解析:結構複製與資料複製的差異

     編輯:ASP.NET 基礎

前言

System.Data.DataTable 提供兩個易混淆的方法:Clone() 與 Copy()。兩者皆回傳新的 DataTable 實例,但複製深度截然不同。本文從定義、程式碼驗證、記憶體行為、實務適用場景完整剖析。

核心差異一覽

方法 複製內容 資料列 約束/關聯 典型用途
Clone() 僅結構:欄位定義、資料型別、UniqueConstraint、ForeignKeyConstraint、ExtendedProperties 無 (空表) 是 建立相同結構的空表、效能優於 Copy、遷移 Schema
Copy() 結構 + 所有資料:含每一筆 DataRow、RowState、RowError 完整複製 (深層) 是 備份、離線編輯後合併、跨 Thread 傳遞資料快照

程式碼驗證


using System;
using System.Data;
using System.Data.SqlClient;

class DataTableCloneCopyDemo
{
    static string ConnStr = "Server=.\\SQLEXPRESS;Database=TestDB;Integrated Security=True;";

    static void Main()
    {
        using (var conn = new SqlConnection(ConnStr))
        using (var da = new SqlDataAdapter("SELECT TOP 5 Id, Name, Age FROM Users", conn))
        {
            var dt = new DataTable();
            da.Fill(dt);
            Console.WriteLine($"原始表: Rows={dt.Rows.Count}, Columns={dt.Columns.Count}");

            // Clone
            var dtClone = dt.Clone();
            Console.WriteLine($"Clone(): Rows={dtClone.Rows.Count}, Columns={dtClone.Columns.Count}");
            PrintSchema(dtClone);

            // Copy
            var dtCopy = dt.Copy();
            Console.WriteLine($"Copy(): Rows={dtCopy.Rows.Count}, Columns={dtCopy.Columns.Count}");
            PrintData(dtCopy);
        }
    }

    static void PrintSchema(DataTable t)
    {
        foreach (DataColumn c in t.Columns)
            Console.Write($"  {c.ColumnName}({c.DataType.Name})");
        Console.WriteLine();
    }

    static void PrintData(DataTable t)
    {
        foreach (DataRow r in t.Rows)
            Console.WriteLine($"  {r[0]}\t{r[1]}\t{r[2]}");
    }
}

輸出結果

原始表: Rows=5, Columns=3
Clone(): Rows=0, Columns=3
  Id(Int32)  Name(String)  Age(Int32)
Copy(): Rows=5, Columns=3
  1   Alice   25
  2   Bob     30
  3   Carol   28
  4   Dave    35
  5   Eve     22

記憶體與效能分析

  • Clone():只配置結構中繼資料,極快,記憶體占用極小 (KB 級)。
  • Copy():需配置每一列的資料緩衝區,時間/記憶體隨資料量線性增長。大表 (10 萬列+) 複製可能耗時數百毫秒並佔用數十 MB。
  • RowState 複製:Copy() 保留 Added/Modified/Deleted/Unchanged 狀態,適合離線編輯後 Merge() 回主表。

進階:Clone + ImportRow 組合 (高效能篩選複製)

若需「複製結構 + 部分資料」,不要 先 Copy() 再刪除列,應用 Clone() + ImportRow():


// 需求:複製 Age > 30 的列
var filtered = dt.Clone(); // 只要結構
foreach (DataRow row in dt.Select("Age > 30"))
{
    filtered.ImportRow(row); // 深層複製單列 (含 RowState)
}
// filtered 現在只有符合條件的列,效能遠優於 Copy() + Delete()

實務應用場景決策樹

需要新 DataTable
│
├─ 只要結構 (建立暫存表、定義 Schema) → Clone()
│
└─ 需要資料
    │
    ├─ 全部資料 (備份、快照、跨域傳遞) → Copy()
    │
    └─ 部分資料 (篩選、分頁、條件複製) → Clone() + ImportRow() / LoadDataRow()

常見誤區

  1. 以為 Clone() 複製資料:最常見 Bug,導致後續處理空表。
  2. Copy() 後修改複製表影響原表:Copy() 是深層複製,修改 dtCopy.Rows[0]["Name"] 不會影響 dt。但若欄位型別為參考型別 (如 byte[]、自訂類別),則複製的是參考,修改物件內容會互相影響。
  3. 大量資料用 Copy() 導致 OOM:分批處理或改用 Clone() + ImportRow 流式處理。
  4. 忽略 Constraint 複製:兩者皆複製 Constraints 集合,但 ForeignKeyConstraint 參考的父表若不在同一 DataSet 會失效。

ASP.NET WebForms 實務範例:GridView 編輯緩衝


protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        // 1. 從 DB 載入主表
        DataTable master = GetDataFromDB();
        Session["MasterTable"] = master;
        gv.DataSource = master;
        gv.DataBind();
    }
}

protected void gv_RowEditing(object sender, GridViewEditEventArgs e)
{
    gv.EditIndex = e.NewEditIndex;
    gv.DataSource = Session["MasterTable"];
    gv.DataBind();
}

protected void gv_RowUpdating(object sender, GridViewUpdateEventArgs e)
{
    DataTable master = (DataTable)Session["MasterTable"];
    DataRow row = master.Rows[e.RowIndex];
    
    // 2. 直接更新主表 (或 Clone 一份離線編輯)
    row["Name"] = e.NewValues["Name"];
    row["Age"] = e.NewValues["Age"];
    
    gv.EditIndex = -1;
    gv.DataSource = master;
    gv.DataBind();
}

// 若需「取消所有變更」功能:
protected void btnRevert_Click(object sender, EventArgs e)
{
    // 3. 從 Session 取得原始快照 (Copy)
    DataTable original = ((DataTable)Session["MasterTable"]).Copy();
    Session["MasterTable"] = original;
    gv.DataSource = original;
    gv.DataBind();
}

總結

  • Clone() = Schema 只有,極快、記憶體小,適用建立空表、篩選複製基底。
  • Copy() = Schema + Data 完整,深層複製含 RowState,適用備份、快照、離線編輯。
  • 部分複製首選 Clone() + ImportRow(),避免 Copy() 後刪除列的效能浪費。
  • 參考型別欄位複製時注意淺複製特性,必要時手動深層複製該欄位值。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved