LINQ to DataSet 專為離線資料 (DataSet/DataTable) 設計,屬於 LINQ to ADO.NET 子集。核心擴充方法集中在兩個靜態類別:
System.Data.DataTableExtensions:DataTable、DataView、IEnumerable<DataRow> 互轉。System.Data.DataRowExtensions:強型別欄位存取 Field<T>() / SetField<T>()。| 方法 | 用途 |
|---|---|
AsEnumerable() | DataTable → EnumerableRowCollection<DataRow> (實作 IEnumerable<DataRow>),啟用 LINQ 查詢 |
AsDataView() | DataTable 或查詢結果 → DataView,支援資料繫結 |
CopyToDataTable() | 查詢結果 (IEnumerable<DataRow>) → 新 DataTable 或合併至現有 Table |
// 無參數:自動建立 Original/Current 版本
var newTable = query.CopyToDataTable();
// 帶 LoadOption:控制版本建立行為
query.CopyToDataTable(targetTable, LoadOption.OverwriteChanges); // 更新 Current + Original
query.CopyToDataTable(targetTable, LoadOption.PreserveChanges); // 僅更新 Original
query.CopyToDataTable(targetTable, LoadOption.Upsert); // 僅更新 Current
關鍵:合併時必須設定目標 Table PrimaryKey,否則僅單純 Append。
// 讀取:支援 Column、Index、Name、版本
string name = row.Field<string>("Name");
string nameOrig = row.Field<string>("Name", DataRowVersion.Original);
// 寫入:自動處理 null → DBNull.Value
row.SetField<string>("Name", null); // 自動轉為 DBNull.Value
優勢:
DBNull.Value ⇄ null 雙向轉換(Field 讀取 DBNull 回傳 null;SetField 寫入 null 存 DBNull)。DBNull 轉型拋例外。Distinct、Union、Except、Intersect、SequenceEqual 預設用參考比較,導致內容相同但非同一物件的 DataRow 視為不同。必須傳入 DataRowComparer.Default 進行值比較(先比欄位數,再逐欄位 Equals)。
public static void Test() {
var students = new[] {
new Student { Id = 1, Name = "Lazy Bee" },
new Student { Id = 7, Name = "Flying Wind" },
new Student { Id = 13, Name = "PiPi Zhu" },
new Student { Id = 72, Name = "Chong Chong" }
};
DataTable originalTable = GetDataTable(students);
// 1. 原始表無 Original 版本,存取拋例外
// 2. 用 CopyToDataTable 建立版本
DataTable newTable = originalTable.AsEnumerable().CopyToDataTable();
// 3. 修改資料
newTable.AsEnumerable()
.Single(r => r.Field<string>("Name") == "PiPi Zhu")
.SetField("Name", "George Oscar Bluth");
// 4. 設 null
newTable.AsEnumerable()
.Single(r => r.Field<int>("Id") == 13)
.SetField<string>("Name", null);
// 5. 合併回原表(需 PrimaryKey)
originalTable.PrimaryKey = new[] { originalTable.Columns["Id"] };
newTable.AsEnumerable().CopyToDataTable(originalTable, LoadOption.OverwriteChanges);
// 6. 去重(必須用 DataRowComparer.Default)
var distinct = originalTable.AsEnumerable().Distinct(DataRowComparer.Default);
}
Distinct/Union/Except/Intersect/SequenceEqual、GroupBy Key 為 DataRow 時,必須用 DataRowComparer.Default。null 自動轉 DBNull.Value。DBNull.Value 自動回傳 null,強型別免拆箱。AcceptChanges()、CopyToDataTable()、或先 HasVersion 判斷。