在離線 DataSet 中實現類 SQL JOIN 效果,核心是建立 DataRelation 關聯兩張 DataTable,再透過 GetChildRows 或繫結控件屬性導航關聯資料。
private DataSet PrepareDataSet()
{
var ds = new DataSet();
// Customers 表
var tbCustomers = new DataTable("Customers");
tbCustomers.Columns.AddRange(new[] {
new DataColumn("CustomerID"),
new DataColumn("CompanyName")
});
// Orders 表
var tbOrders = new DataTable("Orders");
tbOrders.Columns.AddRange(new[] {
new DataColumn("CustomerID"),
new DataColumn("OrderID", typeof(int)),
new DataColumn("OrderDate", typeof(DateTime))
});
ds.Tables.AddRange(new[] { tbCustomers, tbOrders });
// 建立關聯:CustomerID 1 對多 Order
ds.Relations.Add("Customers_Orders_Relation",
tbCustomers.Columns["CustomerID"],
tbOrders.Columns["CustomerID"]);
// 填充測試資料
for (int x = 0; x < 10; x++)
{
var customer = tbCustomers.NewRow();
customer[0] = "CustomerID:" + x;
customer[1] = "Company:" + x;
tbCustomers.Rows.Add(customer);
for (int y = 0; y < 5; y++)
{
var order = tbOrders.NewRow();
order[0] = "CustomerID:" + x;
order[1] = (y + 1) * 1000;
order[2] = DateTime.Now;
tbOrders.Rows.Add(order);
}
}
return ds;
}
// 頁面載入
protected override void OnLoad(EventArgs e)
{
DataSet ds = PrepareDataSet();
gvCustomers.DataSource = ds.Tables[0];
gvOrders.DataSource = ds.Tables[1];
DataBind();
}
ASPX 中可用巢狀 Repeater/GridView,內層繫結 '<%# ((DataRowView)Container.DataItem).CreateChildView("Customers_Orders_Relation") %>' 顯示從表資料。
foreach (DataRow customer in ds.Tables["Customers"].Rows)
{
Console.WriteLine(customer["CompanyName"]);
foreach (DataRow order in customer.GetChildRows("Customers_Orders_Relation"))
{
Console.WriteLine($" OrderID: {order["OrderID"]}, Date: {order["OrderDate"]}");
}
}
| 優點 | 缺點 |
|---|---|
| 離線操作、減少資料庫往返 | 記憶體佔用大,不適合海量資料 |
| 關聯導航語意清晰 | 無法像 SQL JOIN 直接投影扁平化結果 |
| 支援階層式 UI 繫結 | 關聯維護成本高 (手動同步 FK) |
適用於中小資料量、主從表同步編輯、報表離線生成等場景。大數據量請在資料庫層完成 JOIN 再填入 DataSet。