DataSet 與 DataTable 是 ADO.NET 離線資料架構的核心,支援多資料表、關聯、條件約束、資料檢視與 XML 序列化。本文系統整理從建立結構、填入資料、查詢修改、狀態追蹤、條件約束、XML 互轉到效能優化的完整操作模式,附大量可直接複製的代碼片段。
DataSet ds = new DataSet("MyDataSet");
DataTable dt = ds.Tables.Add("Customers");
dt.Columns.Add("CustomerID", typeof(string)).MaxLength = 5;
dt.Columns.Add("CompanyName", typeof(string));
dt.PrimaryKey = new[] { dt.Columns["CustomerID"] }; // 設定主鍵
// 自動遞增欄位
DataColumn idCol = dt.Columns.Add("OrderID", typeof(int));
idCol.AutoIncrement = true;
idCol.AutoIncrementSeed = -1;
idCol.AutoIncrementStep = -1;
idCol.ReadOnly = true;
// 運算欄位
dt.Columns.Add("ItemTotal", typeof(decimal), "Quantity * UnitPrice");
using (var da = new SqlDataAdapter("SELECT * FROM Orders", connStr))
{
da.Fill(ds, "Orders"); // 自動建立 DataTable 並填入資料
}
// 取得第一個 DataTable
DataTable tbl = ds.Tables[0]; // 或 ds.Tables["Orders"]
// 列舉欄位名稱
foreach (DataColumn col in tbl.Columns)
Console.WriteLine(col.ColumnName);
// 取得第一列資料
DataRow row = tbl.Rows[0];
Console.WriteLine(row["OrderID"]);
// 列舉該列所有欄位值
foreach (DataColumn col in tbl.Columns)
Console.WriteLine(row[col]);
// 列舉所有列
foreach (DataRow r in tbl.Rows)
DisplayRow(r);
DataRow newRow = tbl.NewRow();
newRow["CustomerID"] = "ALFKI";
newRow["CompanyName"] = "Alfreds";
tbl.Rows.Add(newRow);
// 或使用物件陣列
tbl.Rows.Add("ALFKI", "Alfreds", "Maria", "Berlin");
DataRow row = tbl.Rows.Find("ANTON");
if (row != null) {
row.BeginEdit();
row["CompanyName"] = "NewName";
row["ContactName"] = "NewContact";
row.EndEdit(); // 變更標記為 Modified
}
DataRow row = tbl.Rows.Find("ALFKI");
row.Delete(); // 標記為 Deleted,實際移除需 AcceptChanges 或 DataAdapter.Update
Detached:新建未加入集合Added:已加入,未 AcceptChangesUnchanged:已同步Modified:已編輯Deleted:已標記刪除row["CompanyName"] = "New";
Console.WriteLine(row["CompanyName", DataRowVersion.Current]); // New
Console.WriteLine(row["CompanyName", DataRowVersion.Original]); // Old
// Unique
dt.Columns["Email"].Unique = true;
// ForeignKey
DataTable parent = ds.Tables["Customers"];
DataTable child = ds.Tables["Orders"];
var fk = new ForeignKeyConstraint(parent.Columns["CustomerID"], child.Columns["CustomerID"]);
child.Constraints.Add(fk);
| 類別 | 常用成員 | 說明 |
|---|---|---|
| DataSet | AcceptChanges()/RejectChanges() | 認可/放棄所有掛起變更 |
GetChanges() | 取得含變更列的新 DataSet(適合傳給 DataAdapter.Update) | |
Merge() | 合併另一 DataSet/DataTable/DataRow[] | |
ReadXml/WriteXml | XML 序列化 | |
HasChanges | 是否有掛起變更 | |
| DataTable | Select(filter, sort) | 依條件篩選排序,回傳 DataRow[] |
Compute(expr, filter) | 聚合運算(Sum, Count 等) | |
DefaultView | 取得 DataView 供排序/篩選/繫結 | |
| DataRow | BeginEdit/EndEdit/CancelEdit | 批次編輯 |
ItemArray | 一次存取/設定所有欄位值 |
// DataSet 寫入 XML(含結構描述)
ds.WriteXml("data.xml", XmlWriteMode.WriteSchema);
// 讀取 XML
DataSet ds2 = new DataSet();
ds2.ReadXml("data.xml");
foreach (DataTable dt in dataSet.Tables)
foreach (DataRow dr in dt.Rows)
foreach (DataColumn dc in dr.Table.Columns)
Console.WriteLine($"{dc.ColumnName} = {dr[dc]}");
DataReader(唯讀、前向、低記憶體)。DataTable.Select 會掃描全表,大量查詢建議建立 DataView 並設定 Sort/RowFilter。BeginEdit/EndEdit 減少事件觸發次數。DataSet 時,考慮 GetChanges() 只傳遞異動資料,降低頻寬。Clone() 只複製結構,Copy() 連資料一起複製。