DataSet 是 ADO.NET 離線架構的核心,宛如記憶體中的微型資料庫,支援多資料表、關聯、條件約束與異動追蹤。本文以 Northwind 資料庫為例,實作「多表填充」、「主從關聯顯示」、「關聯表更新」與「多 Command 交易」四大實戰場景,並揭露 SqlHelper.FillDataset 多表 Bug 修正方案。
DatasetOrders
CREATE PROCEDURE GetCustomerOrdersInfo
AS
SELECT CustomerID, CompanyName, ContactName FROM Customers WHERE CustomerID LIKE 'A%'
SELECT OrderID, OrderDate, CustomerID FROM Orders WHERE CustomerID IN (SELECT CustomerID FROM Customers WHERE CustomerID LIKE 'A%')
SELECT OrderID, ProductID, UnitPrice, Quantity, Discount FROM [Order Details] WHERE OrderID IN (SELECT OrderID FROM Orders WHERE CustomerID IN (SELECT CustomerID FROM Customers WHERE CustomerID LIKE 'A%'))
public void FillCustomerOrdersInfo(DatasetOrders ds)
{
using (var comm = new SqlCommand("GetCustomerOrdersInfo", _conn))
using (var da = new SqlDataAdapter(comm))
{
comm.CommandType = CommandType.StoredProcedure;
da.TableMappings.Add("Table", "Customers");
da.TableMappings.Add("Table1", "Orders");
da.TableMappings.Add("Table2", "Order Details");
da.Fill(ds);
}
}
原始碼邏輯錯誤:
for (int i = 0; i < tableNames.Length; i++)
tableName += (i + 1).ToString(); // 錯誤:Table、Table11、Table111...
修正版:
for (int i = 0; i < tableNames.Length; i++)
da.TableMappings.Add(i == 0 ? "Table" : "Table" + i, tableNames[i]);
或直接呼叫修正後的 `FillDataset` 多載。
// 建構子
_ds.EnforceConstraints = false; // 關閉約束提升填充效能
dataGridCustomers.SetDataBinding(_ds, _ds.Customers.TableName);
dataGridOrders.SetDataBinding(_ds,
_ds.Customers.TableName + "." + _ds.Customers.ChildRelations[0].RelationName);
dataGridOrderDetails.SetDataBinding(_ds,
_ds.Customers.TableName + "." + _ds.Customers.ChildRelations[0].RelationName + "." +
_ds.Orders.ChildRelations[0].RelationName);

public void UpdateAll(DatasetOrders ds)
{
// 假設已設定 DataAdapter 的 Insert/Update/DeleteCommand
// 父表
daCustomers.Update(ds.Customers);
// 子表
daOrders.Update(ds.Orders);
daOrderDetails.Update(ds["Order Details"]);
}
public void BatchUpdateWithTransaction(DatasetOrders ds)
{
_conn.Open();
var tran = _conn.BeginTransaction();
try
{
daCustomers.Update(ds.Customers);
daOrders.Update(ds.Orders);
daOrderDetails.Update(ds["Order Details"]);
tran.Commit();
}
catch
{
tran.Rollback();
throw;
}
finally { _conn.Close(); }
}
using (var comm = new SqlCommand("GetCustomerOrdersInfo", _conn))
{
comm.CommandType = CommandType.StoredProcedure;
_conn.Open();
using (var reader = comm.ExecuteReader())
{
do
{
while (reader.Read())
Console.WriteLine(reader[0]);
} while (reader.NextResult());
}
}
| 場景 | 建議 |
|---|---|
| 大量資料填充 | `EnforceConstraints = false` 填充完再 `true` |
| 頻繁更新 | 使用 `BatchUpdate` 或 `SqlBulkCopy` |
| 長時間交易 | 縮短交易範圍,避免鎖定升級 |
| 型別化 vs 非型別化 | 型別化提供 IntelliSense、編譯期檢查,維護性優 |
DataSet 雖非最新技術,但在離線操作、多表關聯、XML 序列化、Web Service 傳輸等企業級場景仍具不可替代性。掌握 TableMappings、關聯路徑繫結、更新順序與交易控制,即能駕馭複雜多表業務邏輯。