DataGridView顯示主從表示例及注意事項

weixin_34219944發表於2009-08-23
diyblPic
在.NET 的Windows Forms資料處理應用中,經常需要處理主從表情況。例如:SQL Server 2000的Northwind資料庫Custumers表和Orders表中,一個客戶對應多個定單(用關聯式資料庫理論的ER概念模型描述,客戶實體與定 單實體是1:N的關係)。程式設計時,可以用一個DataGridView顯示Customers記錄(主表),另一個DataGridView顯示當前 Customer的定單明細(從表)。當點選主表DataGridView的Customers記錄時,從表DataGridView自動過濾顯示對應 CustomerID的全部Orders記錄(見上圖)。C# 2005/2008中的BindingSource元件和DataSet/DataRelation類提供了一個簡便的處理方法,見如下實現步驟和示例代 碼。
  1. 建立一個DataSet資料集物件,使用DataAdaper填充兩個DataTable表:Customers和Orders,分別包含全部的Customers記錄和Orders記錄。也可直接建立和填充資料表;
  2. 以Custumers的主鍵CustomerID和Orders的外來鍵CustomerIdD建立一個主從DataRelation關係物件,並新增該物件到DataSet中;
  3. 使用兩個BindingSource元件:bs_Customers和bs_Orders,分別連線表資料集DataSet的表Customers和關係DataRelation;
  4. 使用兩個DataGridView元件,分別連線bs_Customers和bs_Orders。
下面是全部程式示例程式碼,測試執行時須有SQL Server 2000的Northwind資料庫,不使用資料庫且直接建立資料表的程式碼參見本文最後給出的簡例。using System;
using System.Data;
using System.Data.SqlClient;
using System.Windows.Forms;

namespace WindowsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection();
SqlConnectionStringBuilder ssb = new SqlConnectionStringBuilder();
conn.ConnectionString =
"Data Source=localhost; Initial Catalog=Northwind; Integrated Security = True;";
conn.Open();

DataSet dbSet = new DataSet(); // 建立資料集
using (SqlDataAdapter da = new SqlDataAdapter("select * from Customers", conn))
{
da.Fill(dbSet, "Customers"); // 填充一個 Customers 表
}
using (SqlDataAdapter da = new SqlDataAdapter("select * from Orders", conn))
{
da.Fill(dbSet, "Orders"); // 填充一個 Orders 表
}

DataColumn parentCol = dbSet.Tables["Customers"].Columns["CustomerID"];
DataColumn childCol = dbSet.Tables["Orders"].Columns["CustomerID"];
DataRelation relation =
new DataRelation("FK_Customers_Orders", parentCol, childCol); // 建立主從關係
dbSet.Relations.Add(relation); // 新增主從關係到資料集中

BindingSource bs_Customers = new BindingSource(); // 建立繫結源
BindingSource bs_Orders = new BindingSource();

bs_Customers.DataSource = dbSet;
bs_Customers.DataMember = "Customers"; // 繫結到資料來源——主表

bs_Orders.DataSource = bs_Customers;
bs_Orders.DataMember = "FK_Customers_Orders"; // 繫結到關係——從表,注意:區分大小寫

dataGridView1.DataSource = bs_Customers; // DataGridView 顯示
dataGridView2.DataSource = bs_Orders;
}
}
}
與主表的常規繫結方式不同,從表bs_Orders的資料來源和資料成員的繫結技巧是:
  • http://msnpiki.msnfanatic.com/index.php/Main_Page-->
  • rgin-left: 0px; padding-top: 2px; padding-right: 0px; padding-bottom: 2px; padding-left: 0px; list-style-type: disc; ">bs_Orders.DataSource = bs_Customers,即主表的BindingSource資料來源;
  • bs_Orders.DataMember = "FK_Customers_Orders",即資料集dsSet中的主從關係名。
特 別需要指出:當使用C#2005/2008程式設計時,從表bs_Orders的資料成員DataMember使用的關係名是區分大小寫的。針對上面示例,如 果程式碼改為:DataMember = "fk_Customers_Orders",即修改"FK"為"fk",此時程式並不報錯,並且主表第一條記錄對應的從表記錄是正確的!但瀏覽移動主表 記錄時,從表對應的記錄為空,即使主表移動到第一條記錄時從表也為空!同時還需要指出如下幾點:
  • 並不要求CustomerID是Customers的主鍵和Orders的外來鍵,但要滿足外來鍵的基本條件——主表的CustomerID值唯一,從表的CustomerID值對應主表的某個值。見本文後面給出的程式程式碼;
  • 主從關係是通過資料集DataSet、資料關係DataRelation和資料來源繫結元件BindingSource體現的,與顯示控制元件無關。此時,可以使用ComboBox、ListBox等顯示主從關係情況;
  • 主從關係中的資料表,還可以是定製的物件集,具體使用可以參考《Windows Forms 2.0資料繫結——.NET智慧客戶端資料應用程式設計》一書。
事 實上,.NET通過字串名稱檢索是其特性——索引器,即通過[]設定和訪問物件,許多情況並不區分大小寫,如:DataSet.Table[]、 DataGridViewColumns[]、BindingSource.DataMember(為資料表時)。為何C# 2005/2008中DataRelation的關係名區分大小寫?或者是否是.NET的一個BUG?有興趣者可以進一步探討。下面是直接構建兩個表的程式碼,取代前面從Northwind填充資料的兩個using(){}語句組:private void Form1_Load(object sender, EventArgs e)
{
DataSet dbSet = new DataSet(); // 建立資料集

DataTable customers = new DataTable("Customers"); // 建立客戶表
DataColumn dc = new DataColumn("CustomerID", typeof(int)); // 建立欄位
customers.Columns.Add(dc);
customers.Rows.Add(1); // 新增兩個記錄
customers.Rows.Add(2);

DataTable orders = new DataTable("Orders"); // 建立定單表
dc = new DataColumn("OrderId", typeof(int));
orders.Columns.Add(dc);
dc = new DataColumn("CustomerID", typeof(int));
orders.Columns.Add(dc);

orders.Rows.Add(1, 1); // 新增記錄,注意:CustomerID必須與前面表的某個值相同
orders.Rows.Add(2, 1); // 即要滿足外來鍵的條件
orders.Rows.Add(3, 2);
orders.Rows.Add(4, 2);

dbSet.Tables.Add(customers);
dbSet.Tables.Add(orders);

// 接前面的程式碼部分
}

相關文章