在C# WinForms应用中,主键(Primary Key)和外键(Foreign Key)是数据库关系的核心,用于维护数据完整性并实现表间关联。以下是详细说明及实现步骤:
1. 数据库设计(以SQL Server为例)
主键表(Customers)
sql
CREATE TABLE Customers (
CustomerID INT PRIMARY KEY IDENTITY(1,1),
Name NVARCHAR(100) NOT NULL,
Email NVARCHAR(100)
);
外键表(Orders)
sql
CREATE TABLE Orders (
OrderID INT PRIMARY KEY IDENTITY(1,1),
CustomerID INT NOT NULL,
OrderDate DATETIME NOT NULL,
TotalAmount DECIMAL(10,2),
FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID)
ON DELETE CASCADE -- 级联删除
);
- **
FOREIGN KEY
** 确保Orders.CustomerID
必须存在于Customers.CustomerID
。 - **
ON DELETE CASCADE
** 表示删除客户时自动删除其所有订单。
2. WinForms 数据绑定与关系处理
步骤1:连接数据库并填充DataSet
csharp
using System.Data;
using System.Data.SqlClient;
public partial class MainForm : Form {
private DataSet dataSet = new DataSet();
private SqlDataAdapter customersAdapter, ordersAdapter;
private BindingSource customersBinding = new BindingSource();
private BindingSource ordersBinding = new BindingSource();
public MainForm() {
InitializeComponent();
LoadData();
}
private void LoadData() {
string connectionString = "Your_Connection_String";
// 加载Customers表
customersAdapter = new SqlDataAdapter(
"SELECT * FROM Customers", connectionString);
customersAdapter.Fill(dataSet, "Customers");
// 加载Orders表
ordersAdapter = new SqlDataAdapter(
"SELECT * FROM Orders", connectionString);
ordersAdapter.Fill(dataSet, "Orders");
// 创建表间关系
DataRelation relation = new DataRelation("CustomerOrders",
dataSet.Tables["Customers"].Columns["CustomerID"],
dataSet.Tables["Orders"].Columns["CustomerID"]);
dataSet.Relations.Add(relation);
// 绑定主表到DataGridView
customersBinding.DataSource = dataSet.Tables["Customers"];
dataGridViewCustomers.DataSource = customersBinding;
// 绑定子表到另一个DataGridView(自动筛选)
ordersBinding.DataSource = customersBinding;
ordersBinding.DataMember = "CustomerOrders"; // 使用DataRelation名称
dataGridViewOrders.DataSource = ordersBinding;
}
}
步骤2:使用ComboBox选择外键
在订单编辑窗体中,通过ComboBox选择客户:
csharp
private void OrderForm_Load(object sender, EventArgs e) {
string connectionString = "Your_Connection_String";
using (SqlConnection conn = new SqlConnection(connectionString)) {
SqlDataAdapter adapter = new SqlDataAdapter("SELECT CustomerID, Name FROM Customers", conn);
DataTable customers = new DataTable();
adapter.Fill(customers);
comboBoxCustomer.DisplayMember = "Name"; // 显示客户名称
comboBoxCustomer.ValueMember = "CustomerID"; // 实际值
comboBoxCustomer.DataSource = customers;
}
}
// 保存订单时获取外键值
private void btnSave_Click(object sender, EventArgs e) {
int customerID = (int)comboBoxCustomer.SelectedValue;
// 将customerID插入Orders表
}
3. 数据更新与级联操作
保存更改回数据库
csharp
private void btnSaveAll_Click(object sender, EventArgs e) {
using (SqlConnection conn = new SqlConnection(connectionString)) {
// 更新Customers表
new SqlCommandBuilder(customersAdapter);
customersAdapter.Update(dataSet.Tables["Customers"]);
// 更新Orders表
new SqlCommandBuilder(ordersAdapter);
ordersAdapter.Update(dataSet.Tables["Orders"]);
}
}
4. 处理外键约束错误
当尝试插入无效的外键时,捕获异常:
csharp
try {
ordersAdapter.Update(dataSet.Tables["Orders"]);
} catch (SqlException ex) {
if (ex.Number == 547) { // 外键约束错误代码
MessageBox.Show("错误:所选客户不存在!");
}
}
5. 使用Entity Framework(可选)
若使用ORM工具(如EF Core),可通过导航属性简化操作:
csharp
public class Customer {
public int CustomerID { get; set; }
public string Name { get; set; }
public List<Order> Orders { get; set; } // 导航属性
}
public class Order {
public int OrderID { get; set; }
public int CustomerID { get; set; }
public Customer Customer { get; set; } // 导航属性
}
// 查询客户及其订单
var customers = dbContext.Customers.Include(c => c.Orders).ToList();
关键点总结
- 主键:唯一标识记录,确保数据唯一性。
- 外键:强制引用完整性,关联其他表的主键。
- 数据绑定:使用
DataRelation
和BindingSource
实现主从表联动。 - 级联操作:在数据库或代码中处理关联数据的更新/删除。
- 错误处理:捕获外键约束异常,提供友好提示。