命名空間
using System.Data;
1. 建立 DataTable
// 空表
var dt = new DataTable();
// 指定表名
var dtNamed = new DataTable("Users");
2. 定義欄位
// 方式一:直接加入(名稱 + 型別)
dt.Columns.Add("Id", typeof(int));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("BirthDay", typeof(DateTime));
// 方式二:先建 DataColumn 再加入(可設定更多屬性)
var col = new DataColumn("Email", typeof(string))
{
AllowDBNull = false,
Unique = true,
MaxLength = 100
};
dt.Columns.Add(col);
3. 新增 / 修改資料列
// 3-1 建立空列再賦值
DataRow row = dt.NewRow();
row["Id"] = 1;
row["Name"] = "張三";
row["BirthDay"] = new DateTime(1990, 1, 1);
dt.Rows.Add(row);
// 3-2 直接加入物件陣列(須依欄位順序)
dt.Rows.Add(2, "李四", new DateTime(1992, 5, 20));
// 3-3 修改既有列
dt.Rows[0]["Name"] = "張三豐"; // 依索引
dt.Rows[0]["Email"] = "zhang@example.com"; // 依名稱
4. 讀取資料
// 單一值
string name = dt.Rows[0]["Name"].ToString();
// 遍歷所有列
foreach (DataRow r in dt.Rows)
{
Console.WriteLine($"{r["Id"]}\t{r["Name"]}\t{r["BirthDay"]:yyyy-MM-dd}");
}
5. 篩選與排序
// 5-1 Select 回傳 DataRow[](支援 SQL-like 語法)
DataRow[] adults = dt.Select("BirthDay < '2005-01-01'"); // 成年
DataRow[] likeZhang = dt.Select("Name LIKE '張%'"); // 模糊
DataRow[] sorted = dt.Select("", "BirthDay DESC"); // 排序
// 5-2 DataView 適合繫結 UI 或多重排序
DataView dv = dt.DefaultView;
dv.Sort = "Name ASC, BirthDay DESC";
dv.RowFilter = "Id > 10";
DataTable filteredTable = dv.ToTable(); // 轉回 DataTable
6. 刪除資料列
// 6-1 立即移除(索引會重排)
dt.Rows.RemoveAt(0);
dt.Rows.Remove(dt.Rows[0]);
// 6-2 標記刪除(可回滾)
dt.Rows[0].Delete(); // 標記為 Deleted
dt.AcceptChanges(); // 確認刪除
dt.RejectChanges(); // 取消刪除,還原
// 6-3 批次刪除:倒序迴圈避免索引錯亂
for (int i = dt.Rows.Count - 1; i >= 0; i--)
{
if (Convert.ToInt32(dt.Rows[i]["Id"]) > 100)
dt.Rows.RemoveAt(i);
}
7. 複製與複製結構
// 7-1 完整複製(結構 + 資料)
DataTable fullCopy = dt.Copy();
// 7-2 僅複製結構
DataTable schemaOnly = dt.Clone();
// 7-3 複製特定列到新表
DataTable subset = dt.Clone();
subset.ImportRow(dt.Rows[0]); // 單列
// 或批次
foreach (DataRow r in dt.Select("Id > 10"))
subset.ImportRow(r);
8. 進階技巧
- 主鍵:
dt.PrimaryKey = new[] { dt.Columns["Id"] }; → 可用 dt.Rows.Find(id) 快速查找
- 計算欄位:
dt.Columns.Add("Age", typeof(int), "YEAR(GETDATE()) - YEAR(BirthDay)")
- 事件監聽:
dt.RowChanged += (s, e) => ... 即時驗證/記錄
- 序列化:
dt.WriteXml("data.xml") / dt.ReadXml("data.xml")
效能提示
- 大量新增前呼叫
dt.BeginLoadData(),結束呼叫 dt.EndLoadData()(暫停索引維護)
- 避免在迴圈中頻繁存取
dt.Rows.Count,先存區域變數
- 頻繁篩選同一欄位時,考慮建立
DataView 並設定 Sort