c# Data相关类

在 C# 的ADO.NET中,DataSet是一个核心的内存中数据缓存对象,用于离线存储和处理数据,常被称为 "内存中的数据库"。它可以包含多个数据表、表之间的关系、约束等,独立于数据源(如 SQL Server、Oracle 等),非常适合需要在客户端维护复杂数据关系或离线操作的场景。

一、DataSet 核心概念

DataSet本质是一个离线数据容器,主要特点:

  • 包含一个或多个DataTable(数据表),表结构与数据库表类似

  • 支持DataRelation(表关系),可定义表之间的关联(如主外键关系)

  • 自带数据架构信息(Schema),记录字段类型、约束等元数据

  • 独立于数据源,断开连接后仍可操作数据,适合离线场景

  • 提供数据修改跟踪(通过RowState),便于批量更新回数据源

二、DataSet 相关核心类

DataSet的功能依赖于一系列相关类协同工作,形成完整的内存数据模型:

类名 作用描述
DataSet 顶层容器,包含多个DataTableDataRelation和约束,管理整体数据状态
DataTable 数据表,对应数据库中的表,包含DataColumn(列)和DataRow(行)
DataColumn 表中的列,定义数据类型、默认值、约束(主键、唯一键等)
DataRow 表中的行,存储具体数据,提供数据修改、状态跟踪(新增 / 修改 / 删除)功能
DataRelation 定义两个DataTable之间的关系(如父子表),支持关联数据导航
DataView DataTable的视图,用于排序、筛选、搜索数据,可绑定到 UI 控件
DataAdapter 数据适配器,负责DataSet与数据源之间的同步(填充数据、更新修改)

三、核心类详解与使用示例

1. DataSet 与 DataTable

DataSet是容器,DataTable是其中的表,一个DataSet可包含多个DataTable

示例:创建 DataSet 和 DataTable

复制代码
// 1. 创建DataSet
DataSet dataSet = new DataSet("SalesDB"); // 指定数据集名称
​
// 2. 创建DataTable(客户表)
DataTable customerTable = new DataTable("Customers");
​
// 3. 定义DataColumn(列)
DataColumn idCol = new DataColumn("Id", typeof(int));
idCol.AllowDBNull = false; // 不允许为空
idCol.Unique = true; // 唯一约束
customerTable.Columns.Add(idCol);
​
// 设置主键(可多个列组成复合主键)
customerTable.PrimaryKey = new[] { idCol };
​
// 添加其他列
customerTable.Columns.Add("Name", typeof(string));
customerTable.Columns.Add("RegisterDate", typeof(DateTime));
​
// 4. 向DataTable添加DataRow(行数据)
DataRow row1 = customerTable.NewRow();
row1["Id"] = 1;
row1["Name"] = "张三";
row1["RegisterDate"] = new DateTime(2023, 1, 15);
customerTable.Rows.Add(row1);
​
DataRow row2 = customerTable.NewRow();
row2["Id"] = 2;
row2["Name"] = "李四";
row2["RegisterDate"] = new DateTime(2023, 3, 20);
customerTable.Rows.Add(row2);
​
// 5. 将DataTable添加到DataSet
dataSet.Tables.Add(customerTable);
​
// 验证:输出表信息
Console.WriteLine($"数据集名称:{dataSet.DataSetName}");
Console.WriteLine($"包含表数量:{dataSet.Tables.Count}");
Console.WriteLine($"客户表行数:{dataSet.Tables["Customers"].Rows.Count}");
2. DataRow:操作行数据

DataRow存储具体数据,提供数据访问、修改和状态跟踪功能。

示例:操作 DataRow

复制代码
// 获取前面创建的客户表
DataTable customers = dataSet.Tables["Customers"];
​
// 1. 访问行数据
DataRow firstRow = customers.Rows[0];
Console.WriteLine($"第一个客户:{firstRow["Name"]}(ID:{firstRow["Id"]})");
​
// 2. 修改数据
firstRow["Name"] = "张三三"; // 修改名称
Console.WriteLine($"修改后名称:{firstRow["Name"]}");
​
// 3. 新增行(简化写法)
customers.Rows.Add(3, "王五", new DateTime(2023, 5, 10));
​
// 4. 删除行(标记删除,需调用AcceptChanges才会真正删除)
DataRow rowToDelete = customers.Rows.Find(2); // 通过主键查找
if (rowToDelete != null)
    rowToDelete.Delete();
​
// 5. 查看行状态(新增/修改/删除/未变)
foreach (DataRow row in customers.Rows)
{
    Console.WriteLine($"ID: {row["Id"]}, 状态: {row.RowState}");
}
// 输出:
// ID: 1, 状态: Modified(已修改)
// ID: 2, 状态: Deleted(已删除)
// ID: 3, 状态: Added(新增)
​
// 6. 提交/撤销修改
customers.AcceptChanges(); // 提交所有修改(删除标记行将被移除)
// customers.RejectChanges(); // 撤销所有修改(恢复到上次Accept状态)
3. DataRelation:表关系

DataRelation用于定义两个DataTable之间的关联(如订单表与客户表的 "一对多" 关系),支持通过父行查找子行。

示例:创建表关系

复制代码
// 1. 创建订单表
DataTable orderTable = new DataTable("Orders");
orderTable.Columns.Add("OrderId", typeof(int));
orderTable.Columns.Add("CustomerId", typeof(int)); // 外键(关联Customers表的Id)
orderTable.Columns.Add("Amount", typeof(decimal));
orderTable.PrimaryKey = new[] { orderTable.Columns["OrderId"] };
​
// 添加订单数据
orderTable.Rows.Add(1001, 1, 999.99m); // 客户1的订单
orderTable.Rows.Add(1002, 1, 1599.50m); // 客户1的另一个订单
orderTable.Rows.Add(1003, 3, 599.00m); // 客户3的订单
dataSet.Tables.Add(orderTable);
​
// 2. 创建关系(客户表 -> 订单表:一对多)
DataRelation customerOrderRel = new DataRelation(
    "Customer_Order", // 关系名称
    dataSet.Tables["Customers"].Columns["Id"], // 父表主键
    dataSet.Tables["Orders"].Columns["CustomerId"] // 子表外键
);
dataSet.Relations.Add(customerOrderRel);
​
// 3. 通过关系导航数据(查找客户1的所有订单)
DataRow customer = dataSet.Tables["Customers"].Rows.Find(1);
if (customer != null)
{
    // 获取子行(订单)
    DataRow[] orders = customer.GetChildRows(customerOrderRel);
    Console.WriteLine($"客户 {customer["Name"]} 的订单数量:{orders.Length}");
    foreach (DataRow order in orders)
    {
        Console.WriteLine($"订单ID:{order["OrderId"]},金额:{order["Amount"]}");
    }
}
​
// 4. 通过子行查找父行(查找订单1001的客户)
DataRow order = dataSet.Tables["Orders"].Rows.Find(1001);
if (order != null)
{
    DataRow parentCustomer = order.GetParentRow(customerOrderRel);
    Console.WriteLine($"订单1001的客户:{parentCustomer["Name"]}");
}
4. DataView:数据视图

DataViewDataTable的可定制视图,支持排序、筛选、搜索,常用于 UI 绑定(如DataGridView)。

示例:使用 DataView 筛选和排序

复制代码
// 获取订单表
DataTable orders = dataSet.Tables["Orders"];
​
// 1. 创建DataView(默认包含所有行)
DataView orderView = new DataView(orders);
​
// 2. 筛选:只显示金额>1000的订单
orderView.RowFilter = "Amount > 1000";
​
// 3. 排序:按金额降序
orderView.Sort = "Amount DESC";
​
// 4. 遍历视图数据
Console.WriteLine("筛选并排序后的订单:");
foreach (DataRowView rowView in orderView)
{
    Console.WriteLine($"订单ID:{rowView["OrderId"]},金额:{rowView["Amount"]}");
}
​
// 5. 绑定到UI控件(如WinForm的DataGridView)
// dataGridView1.DataSource = orderView;
5. DataAdapter:同步数据源

DataAdapterDataSet与数据源之间的桥梁,负责将数据源数据填充到DataSet,并将DataSet的修改更新回数据源。

示例:用 DataAdapter 填充和更新数据

复制代码
string connectionString = "Server=.;Database=SalesDB;Integrated Security=True;";
​
// 1. 创建DataAdapter(关联查询命令)
using (SqlDataAdapter adapter = new SqlDataAdapter())
{
    // 查询命令(用于填充数据)
    adapter.SelectCommand = new SqlCommand(
        "SELECT Id, Name, RegisterDate FROM Customers", 
        new SqlConnection(connectionString)
    );
​
    // 更新命令(用于将修改同步回数据库,可自动生成或手动指定)
    SqlCommandBuilder cmdBuilder = new SqlCommandBuilder(adapter); // 自动生成增删改命令
​
    // 2. 填充DataSet
    DataSet dbDataSet = new DataSet();
    adapter.Fill(dbDataSet, "Customers"); // 填充到DataSet的"Customers"表
​
    // 3. 修改数据(在内存中)
    DataTable dbCustomers = dbDataSet.Tables["Customers"];
    dbCustomers.Rows[0]["Name"] = "张三更新"; // 修改
    dbCustomers.Rows.Add(4, "赵六", DateTime.Now); // 新增
    dbCustomers.Rows[1].Delete(); // 删除
​
    // 4. 将修改更新回数据库(根据RowState批量执行增删改)
    int updatedRows = adapter.Update(dbDataSet, "Customers");
    Console.WriteLine($"成功更新 {updatedRows} 条记录到数据库");
}

四、DataSet 与相关类的关系总结

  1. 层级关系DataSet包含DataTableDataTable包含DataColumnDataRowDataRelation关联多个DataTable

  2. 数据流转DataAdapter从数据源读取数据填充DataSet,修改后再通过DataAdapter更新回数据源。

  3. UI 交互DataView作为DataTable的视图,简化 UI 绑定和数据展示。

五、使用场景与注意事项

  • 适用场景:离线数据处理、复杂数据关系维护(多表关联)、需要缓存数据的客户端应用。

  • 局限性 :内存占用较大,不适合处理超大量数据(此时推荐DataReader);离线操作可能导致数据一致性问题(需处理并发冲突)。

  • 性能建议 :只加载需要的数据;避免频繁创建DataSet;批量更新时使用DataAdapter.Update而非逐条操作。

通过DataSet及其相关类,开发者可以在内存中构建完整的关系型数据模型,灵活实现离线数据处理和复杂业务逻辑。

相关推荐
科技小花2 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸2 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain2 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希2 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神2 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员3 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java3 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿3 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb
不知名的老吴3 小时前
Redis的延迟瓶颈:TCP栈开销无法避免
数据库·redis·缓存
YOU OU3 小时前
三大范式和E-R图
数据库