c#中DataSet類的具體使用
在 C# 的ADO.NET體系中,DataSet是一個內(nèi)存中的數(shù)據(jù)容器,可視為 “離線數(shù)據(jù)庫”,用于存儲和管理關(guān)系型數(shù)據(jù)(包含表、表關(guān)系、約束等),且獨(dú)立于底層數(shù)據(jù)源(如 SQL Server、MySQL 等)。它是處理復(fù)雜數(shù)據(jù)關(guān)系、離線數(shù)據(jù)操作的核心組件。
一、DataSet 的核心特性
- 離線數(shù)據(jù)存儲:數(shù)據(jù)加載后與數(shù)據(jù)源斷開連接,仍可在內(nèi)存中操作,適合客戶端離線場景。
- 關(guān)系型結(jié)構(gòu):可包含多個
DataTable(數(shù)據(jù)表),表之間通過DataRelation(關(guān)系)關(guān)聯(lián),支持主外鍵邏輯。 - 數(shù)據(jù)狀態(tài)跟蹤:自動記錄數(shù)據(jù)行的修改狀態(tài)(新增、修改、刪除),便于批量同步回?cái)?shù)據(jù)源。
- 架構(gòu)獨(dú)立性:自帶數(shù)據(jù)架構(gòu)(
Schema),記錄字段類型、約束(主鍵、唯一鍵等),不依賴數(shù)據(jù)源元數(shù)據(jù)。
二、DataSet 的基本結(jié)構(gòu)
DataSet的結(jié)構(gòu)類似小型數(shù)據(jù)庫,核心組成如下:
- Tables集合:存儲多個DataTable對象(數(shù)據(jù)表),每個DataTable對應(yīng)一組結(jié)構(gòu)化數(shù)據(jù)。
- Relations集合:存儲DataRelation對象,定義DataTable之間的關(guān)聯(lián)關(guān)系(如 “客戶 - 訂單” 的一對多關(guān)系)。
- ExtendedProperties:存儲自定義鍵值對信息(如數(shù)據(jù)集描述、創(chuàng)建時間等)。
三、DataSet 的常用方法與屬性
| 方法 / 屬性 | 說明 |
|---|---|
| Tables | 獲取DataTableCollection,用于訪問或管理包含的DataTable |
| Relations | 獲取DataRelationCollection,用于管理表之間的關(guān)系 |
| DataSetName | 獲取或設(shè)置數(shù)據(jù)集名稱 |
| AcceptChanges() | 提交所有數(shù)據(jù)修改(將RowState重置為Unchanged) |
| RejectChanges() | 撤銷所有未提交的修改(恢復(fù)到上次AcceptChanges后的狀態(tài)) |
| Merge(DataSet) | 將另一個DataSet的數(shù)據(jù)合并到當(dāng)前數(shù)據(jù)集(常用于合并離線修改) |
| Clear() | 清空所有表中的數(shù)據(jù)(保留表結(jié)構(gòu)) |
| GetXml() | 將數(shù)據(jù)集內(nèi)容轉(zhuǎn)換為 XML 字符串 |
| ReadXml(string) | 從 XML 文件加載數(shù)據(jù)到數(shù)據(jù)集 |
四、使用示例:完整操作流程
以下通過 “客戶 - 訂單” 數(shù)據(jù)模型,展示DataSet的創(chuàng)建、數(shù)據(jù)操作、關(guān)系管理和持久化的完整流程。
1. 創(chuàng)建 DataSet 并定義表結(jié)構(gòu)
// 1. 創(chuàng)建DataSet
DataSet salesDataSet = new DataSet("SalesData"); // 數(shù)據(jù)集名稱
?
// 2. 創(chuàng)建客戶表(Customers)
DataTable customerTable = new DataTable("Customers");
// 定義列(含主鍵)
customerTable.Columns.Add("CustomerId", typeof(int)); // 主鍵列
customerTable.Columns.Add("Name", typeof(string));
customerTable.Columns.Add("Phone", typeof(string));
// 設(shè)置主鍵
customerTable.PrimaryKey = new[] { customerTable.Columns["CustomerId"] };
?
// 3. 創(chuàng)建訂單表(Orders)
DataTable orderTable = new DataTable("Orders");
orderTable.Columns.Add("OrderId", typeof(int)); // 主鍵列
orderTable.Columns.Add("CustomerId", typeof(int)); // 外鍵(關(guān)聯(lián)Customers)
orderTable.Columns.Add("Amount", typeof(decimal));
orderTable.Columns.Add("OrderDate", typeof(DateTime));
orderTable.PrimaryKey = new[] { orderTable.Columns["OrderId"] };
?
// 4. 將表添加到DataSet
salesDataSet.Tables.Add(customerTable);
salesDataSet.Tables.Add(orderTable);
?
// 驗(yàn)證結(jié)構(gòu)
Console.WriteLine($"數(shù)據(jù)集名稱:{salesDataSet.DataSetName}");
Console.WriteLine($"包含表數(shù)量:{salesDataSet.Tables.Count}"); // 輸出:22. 填充數(shù)據(jù)與操作行
// 1. 向客戶表添加數(shù)據(jù)
DataTable customers = salesDataSet.Tables["Customers"];
customers.Rows.Add(1, "張三", "13800138000"); // 直接傳值(按列順序)
customers.Rows.Add(2, "李四", "13900139000");
?
// 2. 向訂單表添加數(shù)據(jù)
DataTable orders = salesDataSet.Tables["Orders"];
orders.Rows.Add(1001, 1, 999.99m, new DateTime(2024, 1, 15)); // 張三的訂單
orders.Rows.Add(1002, 1, 1599.50m, new DateTime(2024, 3, 20)); // 張三的訂單
orders.Rows.Add(1003, 2, 599.00m, new DateTime(2024, 5, 10)); // 李四的訂單
?
// 3. 修改數(shù)據(jù)
DataRow zhangsanRow = customers.Rows.Find(1); // 通過主鍵查找
zhangsanRow["Phone"] = "13812345678"; // 修改手機(jī)號
?
// 4. 刪除數(shù)據(jù)
DataRow orderToDelete = orders.Rows.Find(1003); // 查找訂單1003
if (orderToDelete != null)
orderToDelete.Delete(); // 標(biāo)記刪除(未真正刪除,需AcceptChanges確認(rèn))
?
// 5. 查看行狀態(tài)(跟蹤修改)
foreach (DataRow row in customers.Rows)
{
Console.WriteLine($"客戶ID: {row["CustomerId"]}, 狀態(tài): {row.RowState}");
}
// 輸出:
// 客戶ID: 1, 狀態(tài): Modified(已修改)
// 客戶ID: 2, 狀態(tài): Unchanged(未修改)3. 定義表關(guān)系與數(shù)據(jù)導(dǎo)航
通過DataRelation建立表之間的關(guān)聯(lián),實(shí)現(xiàn)父子數(shù)據(jù)的快速導(dǎo)航。
// 1. 創(chuàng)建“客戶-訂單”關(guān)系(一對多)
DataRelation customerOrderRel = new DataRelation(
"FK_Customer_Order", // 關(guān)系名稱
salesDataSet.Tables["Customers"].Columns["CustomerId"], // 父表主鍵
salesDataSet.Tables["Orders"].Columns["CustomerId"] // 子表外鍵
);
// 添加關(guān)系到DataSet
salesDataSet.Relations.Add(customerOrderRel);
?
// 2. 通過父行查找子行(查詢張三的所有訂單)
DataRow zhangsan = customers.Rows.Find(1);
if (zhangsan != null)
{
// 獲取張三的所有訂單(子行)
DataRow[] zhangsanOrders = zhangsan.GetChildRows(customerOrderRel);
Console.WriteLine($"客戶 {zhangsan["Name"]} 的訂單數(shù)量:{zhangsanOrders.Length}");
foreach (DataRow order in zhangsanOrders)
{
Console.WriteLine($"訂單ID:{order["OrderId"]},金額:{order["Amount"]}");
}
}
?
// 3. 通過子行查找父行(查詢訂單1001的客戶)
DataRow order1001 = orders.Rows.Find(1001);
if (order1001 != null)
{
DataRow customer = order1001.GetParentRow(customerOrderRel);
Console.WriteLine($"訂單1001的客戶:{customer["Name"]}"); // 輸出:張三
}4. 數(shù)據(jù)持久化(XML 導(dǎo)入 / 導(dǎo)出)
DataSet支持直接與 XML 互轉(zhuǎn),方便數(shù)據(jù)持久化或傳輸。
// 1. 將數(shù)據(jù)導(dǎo)出為XML(含結(jié)構(gòu)和數(shù)據(jù))
string xmlData = salesDataSet.GetXml();
Console.WriteLine("XML數(shù)據(jù):");
Console.WriteLine(xmlData);
?
// 2. 保存到XML文件
salesDataSet.WriteXml("SalesData.xml"); // 僅數(shù)據(jù)
salesDataSet.WriteXmlSchema("SalesDataSchema.xml"); // 僅結(jié)構(gòu)(Schema)
?
// 3. 從XML文件加載數(shù)據(jù)
DataSet newDataSet = new DataSet();
newDataSet.ReadXml("SalesData.xml");
newDataSet.ReadXmlSchema("SalesDataSchema.xml"); // 加載結(jié)構(gòu)確保類型正確
Console.WriteLine($"從XML加載的客戶表行數(shù):{newDataSet.Tables["Customers"].Rows.Count}");5. 與數(shù)據(jù)庫同步(結(jié)合 DataAdapter)
DataSet的修改可通過DataAdapter批量更新回?cái)?shù)據(jù)源,利用其狀態(tài)跟蹤功能自動生成增刪改命令。
string connectionString = "Server=.;Database=SalesDB;Integrated Security=True;";
?
// 1. 創(chuàng)建DataAdapter(作為DataSet與數(shù)據(jù)庫的橋梁)
using (SqlDataAdapter adapter = new SqlDataAdapter())
{
// 設(shè)置查詢命令(用于從數(shù)據(jù)庫加載數(shù)據(jù))
adapter.SelectCommand = new SqlCommand(
"SELECT CustomerId, Name, Phone FROM Customers",
new SqlConnection(connectionString)
);
?
// 自動生成增刪改命令(需引用System.Data.SqlClient)
SqlCommandBuilder cmdBuilder = new SqlCommandBuilder(adapter);
?
// 2. 從數(shù)據(jù)庫填充DataSet
DataSet dbDataSet = new DataSet();
adapter.Fill(dbDataSet, "Customers"); // 填充到"Customers"表
?
// 3. 在內(nèi)存中修改數(shù)據(jù)(模擬用戶操作)
DataTable dbCustomers = dbDataSet.Tables["Customers"];
dbCustomers.Rows[0]["Phone"] = "13888888888"; // 修改
dbCustomers.Rows.Add(3, "王五", "13700137000"); // 新增
dbCustomers.Rows[1].Delete(); // 刪除
?
// 4. 將修改同步回?cái)?shù)據(jù)庫(根據(jù)RowState自動執(zhí)行對應(yīng)SQL)
int updatedRows = adapter.Update(dbDataSet, "Customers");
Console.WriteLine($"成功同步 {updatedRows} 條修改到數(shù)據(jù)庫");
}五、DataSet 的適用場景與局限性
適用場景:
- 離線數(shù)據(jù)處理:客戶端需在無網(wǎng)絡(luò)環(huán)境下操作數(shù)據(jù)(如移動應(yīng)用)。
- 復(fù)雜數(shù)據(jù)關(guān)系:需維護(hù)多表關(guān)聯(lián)(如訂單 - 訂單明細(xì) - 客戶),并頻繁導(dǎo)航數(shù)據(jù)。
- 批量數(shù)據(jù)更新:需一次性提交多條增刪改操作,減少數(shù)據(jù)庫交互次數(shù)。
- 數(shù)據(jù)緩存:重復(fù)使用的數(shù)據(jù)集可緩存到內(nèi)存,提升性能。
局限性:
- 內(nèi)存占用高:數(shù)據(jù)全部加載到內(nèi)存,不適合處理百萬級以上大數(shù)據(jù)。
- 數(shù)據(jù)一致性風(fēng)險:離線操作可能導(dǎo)致與數(shù)據(jù)源數(shù)據(jù)沖突(需額外處理并發(fā))。
- 性能開銷:相比
DataReader(流式讀?。?,初始化和序列化DataSet的開銷更大。
六、總結(jié)
DataSet是 C# 中處理關(guān)系型數(shù)據(jù)的強(qiáng)大工具,其核心價值在于離線數(shù)據(jù)管理和復(fù)雜關(guān)系維護(hù)。通過與DataTable、DataRelation、DataAdapter等類配合,可構(gòu)建完整的內(nèi)存數(shù)據(jù)模型,靈活支持從數(shù)據(jù)加載、修改到同步的全流程。在實(shí)際開發(fā)中,需根據(jù)數(shù)據(jù)量和業(yè)務(wù)場景選擇使用(小批量、多關(guān)系數(shù)據(jù)優(yōu)先,超大數(shù)據(jù)量建議用DataReader)。
到此這篇關(guān)于c#中DataSet類的具體使用的文章就介紹到這了,更多相關(guān)c# DataSet類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

