在 C# 的ADO.NET体系中DataSet是一个内存中的数据容器可视为 “离线数据库”用于存储和管理关系型数据包含表、表关系、约束等且独立于底层数据源如 SQL Server、MySQL 等。它是处理复杂数据关系、离线数据操作的核心组件。一、DataSet 的核心特性离线数据存储数据加载后与数据源断开连接仍可在内存中操作适合客户端离线场景。关系型结构可包含多个DataTable数据表表之间通过DataRelation关系关联支持主外键逻辑。数据状态跟踪自动记录数据行的修改状态新增、修改、删除便于批量同步回数据源。架构独立性自带数据架构Schema记录字段类型、约束主键、唯一键等不依赖数据源元数据。二、DataSet 的基本结构DataSet的结构类似小型数据库核心组成如下Tables集合存储多个DataTable对象数据表每个DataTable对应一组结构化数据。Relations集合存储DataRelation对象定义DataTable之间的关联关系如 “客户 - 订单” 的一对多关系。ExtendedProperties存储自定义键值对信息如数据集描述、创建时间等。三、DataSet 的常用方法与属性方法 / 属性说明Tables获取DataTableCollection用于访问或管理包含的DataTableRelations获取DataRelationCollection用于管理表之间的关系DataSetName获取或设置数据集名称AcceptChanges()提交所有数据修改将RowState重置为UnchangedRejectChanges()撤销所有未提交的修改恢复到上次AcceptChanges后的状态Merge(DataSet)将另一个DataSet的数据合并到当前数据集常用于合并离线修改Clear()清空所有表中的数据保留表结构GetXml()将数据集内容转换为 XML 字符串ReadXml(string)从 XML 文件加载数据到数据集四、使用示例完整操作流程以下通过 “客户 - 订单” 数据模型展示DataSet的创建、数据操作、关系管理和持久化的完整流程。1. 创建 DataSet 并定义表结构123456789101112131415161718192021222324252627// 1. 创建DataSetDataSet salesDataSet newDataSet(SalesData);// 数据集名称// 2. 创建客户表CustomersDataTable customerTable newDataTable(Customers);// 定义列含主键customerTable.Columns.Add(CustomerId,typeof(int));// 主键列customerTable.Columns.Add(Name,typeof(string));customerTable.Columns.Add(Phone,typeof(string));// 设置主键customerTable.PrimaryKey new[] { customerTable.Columns[CustomerId] };// 3. 创建订单表OrdersDataTable orderTable newDataTable(Orders);orderTable.Columns.Add(OrderId,typeof(int));// 主键列orderTable.Columns.Add(CustomerId,typeof(int));// 外键关联CustomersorderTable.Columns.Add(Amount,typeof(decimal));orderTable.Columns.Add(OrderDate,typeof(DateTime));orderTable.PrimaryKey new[] { orderTable.Columns[OrderId] };// 4. 将表添加到DataSetsalesDataSet.Tables.Add(customerTable);salesDataSet.Tables.Add(orderTable);// 验证结构Console.WriteLine($数据集名称{salesDataSet.DataSetName});Console.WriteLine($包含表数量{salesDataSet.Tables.Count});// 输出22. 填充数据与操作行12345678910111213141516171819202122232425262728// 1. 向客户表添加数据DataTable customers salesDataSet.Tables[Customers];customers.Rows.Add(1,张三,13800138000);// 直接传值按列顺序customers.Rows.Add(2,李四,13900139000);// 2. 向订单表添加数据DataTable orders salesDataSet.Tables[Orders];orders.Rows.Add(1001, 1, 999.99m,newDateTime(2024, 1, 15));// 张三的订单orders.Rows.Add(1002, 1, 1599.50m,newDateTime(2024, 3, 20));// 张三的订单orders.Rows.Add(1003, 2, 599.00m,newDateTime(2024, 5, 10));// 李四的订单// 3. 修改数据DataRow zhangsanRow customers.Rows.Find(1);// 通过主键查找zhangsanRow[Phone] 13812345678;// 修改手机号// 4. 删除数据DataRow orderToDelete orders.Rows.Find(1003);// 查找订单1003if(orderToDelete !null)orderToDelete.Delete();// 标记删除未真正删除需AcceptChanges确认// 5. 查看行状态跟踪修改foreach(DataRow rowincustomers.Rows){Console.WriteLine($客户ID: {row[CustomerId]}, 状态: {row.RowState});}// 输出// 客户ID: 1, 状态: Modified已修改// 客户ID: 2, 状态: Unchanged未修改3. 定义表关系与数据导航通过DataRelation建立表之间的关联实现父子数据的快速导航。123456789101112131415161718192021222324252627282930// 1. 创建“客户-订单”关系一对多DataRelation customerOrderRel newDataRelation(FK_Customer_Order,// 关系名称salesDataSet.Tables[Customers].Columns[CustomerId],// 父表主键salesDataSet.Tables[Orders].Columns[CustomerId]// 子表外键);// 添加关系到DataSetsalesDataSet.Relations.Add(customerOrderRel);// 2. 通过父行查找子行查询张三的所有订单DataRow zhangsan customers.Rows.Find(1);if(zhangsan !null){// 获取张三的所有订单子行DataRow[] zhangsanOrders zhangsan.GetChildRows(customerOrderRel);Console.WriteLine($客户 {zhangsan[Name]} 的订单数量{zhangsanOrders.Length});foreach(DataRow orderinzhangsanOrders){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. 数据持久化XML 导入 / 导出DataSet支持直接与 XML 互转方便数据持久化或传输。1234567891011121314// 1. 将数据导出为XML含结构和数据stringxmlData salesDataSet.GetXml();Console.WriteLine(XML数据);Console.WriteLine(xmlData);// 2. 保存到XML文件salesDataSet.WriteXml(SalesData.xml);// 仅数据salesDataSet.WriteXmlSchema(SalesDataSchema.xml);// 仅结构Schema// 3. 从XML文件加载数据DataSet newDataSet newDataSet();newDataSet.ReadXml(SalesData.xml);newDataSet.ReadXmlSchema(SalesDataSchema.xml);// 加载结构确保类型正确Console.WriteLine($从XML加载的客户表行数{newDataSet.Tables[Customers].Rows.Count});5. 与数据库同步结合 DataAdapterDataSet的修改可通过DataAdapter批量更新回数据源利用其状态跟踪功能自动生成增删改命令。12345678910111213141516171819202122232425262728stringconnectionString Server.;DatabaseSalesDB;Integrated SecurityTrue;;// 1. 创建DataAdapter作为DataSet与数据库的桥梁using(SqlDataAdapter adapter newSqlDataAdapter()){// 设置查询命令用于从数据库加载数据adapter.SelectCommand newSqlCommand(SELECT CustomerId, Name, Phone FROM Customers,newSqlConnection(connectionString));// 自动生成增删改命令需引用System.Data.SqlClientSqlCommandBuilder cmdBuilder newSqlCommandBuilder(adapter);// 2. 从数据库填充DataSetDataSet dbDataSet newDataSet();adapter.Fill(dbDataSet,Customers);// 填充到Customers表// 3. 在内存中修改数据模拟用户操作DataTable dbCustomers dbDataSet.Tables[Customers];dbCustomers.Rows[0][Phone] 13888888888;// 修改dbCustomers.Rows.Add(3,王五,13700137000);// 新增dbCustomers.Rows[1].Delete();// 删除// 4. 将修改同步回数据库根据RowState自动执行对应SQLintupdatedRows adapter.Update(dbDataSet,Customers);Console.WriteLine($成功同步 {updatedRows} 条修改到数据库);}五、DataSet 的适用场景与局限性适用场景离线数据处理客户端需在无网络环境下操作数据如移动应用。复杂数据关系需维护多表关联如订单 - 订单明细 - 客户并频繁导航数据。批量数据更新需一次性提交多条增删改操作减少数据库交互次数。数据缓存重复使用的数据集可缓存到内存提升性能。
c#中DataSet类的具体使用
在 C# 的ADO.NET体系中DataSet是一个内存中的数据容器可视为 “离线数据库”用于存储和管理关系型数据包含表、表关系、约束等且独立于底层数据源如 SQL Server、MySQL 等。它是处理复杂数据关系、离线数据操作的核心组件。一、DataSet 的核心特性离线数据存储数据加载后与数据源断开连接仍可在内存中操作适合客户端离线场景。关系型结构可包含多个DataTable数据表表之间通过DataRelation关系关联支持主外键逻辑。数据状态跟踪自动记录数据行的修改状态新增、修改、删除便于批量同步回数据源。架构独立性自带数据架构Schema记录字段类型、约束主键、唯一键等不依赖数据源元数据。二、DataSet 的基本结构DataSet的结构类似小型数据库核心组成如下Tables集合存储多个DataTable对象数据表每个DataTable对应一组结构化数据。Relations集合存储DataRelation对象定义DataTable之间的关联关系如 “客户 - 订单” 的一对多关系。ExtendedProperties存储自定义键值对信息如数据集描述、创建时间等。三、DataSet 的常用方法与属性方法 / 属性说明Tables获取DataTableCollection用于访问或管理包含的DataTableRelations获取DataRelationCollection用于管理表之间的关系DataSetName获取或设置数据集名称AcceptChanges()提交所有数据修改将RowState重置为UnchangedRejectChanges()撤销所有未提交的修改恢复到上次AcceptChanges后的状态Merge(DataSet)将另一个DataSet的数据合并到当前数据集常用于合并离线修改Clear()清空所有表中的数据保留表结构GetXml()将数据集内容转换为 XML 字符串ReadXml(string)从 XML 文件加载数据到数据集四、使用示例完整操作流程以下通过 “客户 - 订单” 数据模型展示DataSet的创建、数据操作、关系管理和持久化的完整流程。1. 创建 DataSet 并定义表结构123456789101112131415161718192021222324252627// 1. 创建DataSetDataSet salesDataSet newDataSet(SalesData);// 数据集名称// 2. 创建客户表CustomersDataTable customerTable newDataTable(Customers);// 定义列含主键customerTable.Columns.Add(CustomerId,typeof(int));// 主键列customerTable.Columns.Add(Name,typeof(string));customerTable.Columns.Add(Phone,typeof(string));// 设置主键customerTable.PrimaryKey new[] { customerTable.Columns[CustomerId] };// 3. 创建订单表OrdersDataTable orderTable newDataTable(Orders);orderTable.Columns.Add(OrderId,typeof(int));// 主键列orderTable.Columns.Add(CustomerId,typeof(int));// 外键关联CustomersorderTable.Columns.Add(Amount,typeof(decimal));orderTable.Columns.Add(OrderDate,typeof(DateTime));orderTable.PrimaryKey new[] { orderTable.Columns[OrderId] };// 4. 将表添加到DataSetsalesDataSet.Tables.Add(customerTable);salesDataSet.Tables.Add(orderTable);// 验证结构Console.WriteLine($数据集名称{salesDataSet.DataSetName});Console.WriteLine($包含表数量{salesDataSet.Tables.Count});// 输出22. 填充数据与操作行12345678910111213141516171819202122232425262728// 1. 向客户表添加数据DataTable customers salesDataSet.Tables[Customers];customers.Rows.Add(1,张三,13800138000);// 直接传值按列顺序customers.Rows.Add(2,李四,13900139000);// 2. 向订单表添加数据DataTable orders salesDataSet.Tables[Orders];orders.Rows.Add(1001, 1, 999.99m,newDateTime(2024, 1, 15));// 张三的订单orders.Rows.Add(1002, 1, 1599.50m,newDateTime(2024, 3, 20));// 张三的订单orders.Rows.Add(1003, 2, 599.00m,newDateTime(2024, 5, 10));// 李四的订单// 3. 修改数据DataRow zhangsanRow customers.Rows.Find(1);// 通过主键查找zhangsanRow[Phone] 13812345678;// 修改手机号// 4. 删除数据DataRow orderToDelete orders.Rows.Find(1003);// 查找订单1003if(orderToDelete !null)orderToDelete.Delete();// 标记删除未真正删除需AcceptChanges确认// 5. 查看行状态跟踪修改foreach(DataRow rowincustomers.Rows){Console.WriteLine($客户ID: {row[CustomerId]}, 状态: {row.RowState});}// 输出// 客户ID: 1, 状态: Modified已修改// 客户ID: 2, 状态: Unchanged未修改3. 定义表关系与数据导航通过DataRelation建立表之间的关联实现父子数据的快速导航。123456789101112131415161718192021222324252627282930// 1. 创建“客户-订单”关系一对多DataRelation customerOrderRel newDataRelation(FK_Customer_Order,// 关系名称salesDataSet.Tables[Customers].Columns[CustomerId],// 父表主键salesDataSet.Tables[Orders].Columns[CustomerId]// 子表外键);// 添加关系到DataSetsalesDataSet.Relations.Add(customerOrderRel);// 2. 通过父行查找子行查询张三的所有订单DataRow zhangsan customers.Rows.Find(1);if(zhangsan !null){// 获取张三的所有订单子行DataRow[] zhangsanOrders zhangsan.GetChildRows(customerOrderRel);Console.WriteLine($客户 {zhangsan[Name]} 的订单数量{zhangsanOrders.Length});foreach(DataRow orderinzhangsanOrders){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. 数据持久化XML 导入 / 导出DataSet支持直接与 XML 互转方便数据持久化或传输。1234567891011121314// 1. 将数据导出为XML含结构和数据stringxmlData salesDataSet.GetXml();Console.WriteLine(XML数据);Console.WriteLine(xmlData);// 2. 保存到XML文件salesDataSet.WriteXml(SalesData.xml);// 仅数据salesDataSet.WriteXmlSchema(SalesDataSchema.xml);// 仅结构Schema// 3. 从XML文件加载数据DataSet newDataSet newDataSet();newDataSet.ReadXml(SalesData.xml);newDataSet.ReadXmlSchema(SalesDataSchema.xml);// 加载结构确保类型正确Console.WriteLine($从XML加载的客户表行数{newDataSet.Tables[Customers].Rows.Count});5. 与数据库同步结合 DataAdapterDataSet的修改可通过DataAdapter批量更新回数据源利用其状态跟踪功能自动生成增删改命令。12345678910111213141516171819202122232425262728stringconnectionString Server.;DatabaseSalesDB;Integrated SecurityTrue;;// 1. 创建DataAdapter作为DataSet与数据库的桥梁using(SqlDataAdapter adapter newSqlDataAdapter()){// 设置查询命令用于从数据库加载数据adapter.SelectCommand newSqlCommand(SELECT CustomerId, Name, Phone FROM Customers,newSqlConnection(connectionString));// 自动生成增删改命令需引用System.Data.SqlClientSqlCommandBuilder cmdBuilder newSqlCommandBuilder(adapter);// 2. 从数据库填充DataSetDataSet dbDataSet newDataSet();adapter.Fill(dbDataSet,Customers);// 填充到Customers表// 3. 在内存中修改数据模拟用户操作DataTable dbCustomers dbDataSet.Tables[Customers];dbCustomers.Rows[0][Phone] 13888888888;// 修改dbCustomers.Rows.Add(3,王五,13700137000);// 新增dbCustomers.Rows[1].Delete();// 删除// 4. 将修改同步回数据库根据RowState自动执行对应SQLintupdatedRows adapter.Update(dbDataSet,Customers);Console.WriteLine($成功同步 {updatedRows} 条修改到数据库);}五、DataSet 的适用场景与局限性适用场景离线数据处理客户端需在无网络环境下操作数据如移动应用。复杂数据关系需维护多表关联如订单 - 订单明细 - 客户并频繁导航数据。批量数据更新需一次性提交多条增删改操作减少数据库交互次数。数据缓存重复使用的数据集可缓存到内存提升性能。