5.1 ADO.NET 基础 5.1 ADO.NET 基础 ADO.NET (ActiveX Data Objects .NET) 是 .NET Framework 中用于访问数据的核心技术。它提供了一组类,允许开发者连接到各种数据源,执行查询,检索结果,并更新数据。ADO.NET 并非单一技术,而是一组协同工作的组件,旨在提供灵活且强大的数据访问能力。 5.1.1 ADO.NET 的架构 ADO.NET 的架构主要包含两个主要组件: .NET Framework Data Provider (数据提供程序): 负责与特定类型的数据源进行通信。每个数据源(例如 SQL Server、Oracle、MySQL)都有一个专门的数据提供程序。
ADO.NET (ActiveX Data Objects .NET) 是 .NET Framework 中用于访问数据的核心技术。它提供了一组类,允许开发者连接到各种数据源,执行查询,检索结果,并更新数据。ADO.NET 并非单一技术,而是一组协同工作的组件,旨在提供灵活且强大的数据访问能力。
ADO.NET 的架构主要包含两个主要组件:
.NET Framework Data Provider (数据提供程序): 负责与特定类型的数据源进行通信。每个数据源(例如 SQL Server、Oracle、MySQL)都有一个专门的数据提供程序。数据提供程序包含以下核心对象:
Connection: 建立与数据源的连接。
Command: 执行 SQL 命令或存储过程。
DataReader: 以只读、只进的方式从数据源读取数据。
DataAdapter: 用于在 DataSet 和数据源之间传输数据。
DataSet: 一个内存中的数据缓存,包含多个 DataTable 对象,DataTable 包含 DataColumn 和 DataRow。DataSet 允许在断开连接的环境中操作数据。
以下是 ADO.NET 架构的简化 Mermaid 图表:
Connection 对象用于建立与数据源的连接。不同的数据提供程序有不同的 Connection 类,例如 SqlConnection (SQL Server), OracleConnection (Oracle), MySqlConnection (MySQL)。
代码示例 (SQL Server):
using System.Data.SqlClient; string connectionString = "Data Source=.;Initial Catalog=MyDatabase;Integrated Security=True"; // 替换为你的连接字符串 SqlConnection connection = new SqlConnection(connectionString); try { connection.Open(); Console.WriteLine("Connection opened successfully!"); } catch (Exception ex) { Console.WriteLine("Error opening connection: " + ex.Message); } finally { if (connection.State == System.Data.ConnectionState.Open) { connection.Close(); Console.WriteLine("Connection closed."); } }
代码解释:
using System.Data.SqlClient;: 引入 SQL Server 数据提供程序。
connectionString: 包含连接到数据库所需的信息,例如服务器地址、数据库名称、身份验证方式。
SqlConnection connection = new SqlConnection(connectionString);: 创建 SqlConnection 对象。
connection.Open();: 打开连接。
try...catch...finally: 确保连接在不再需要时关闭,即使发生异常。
Command 对象用于执行 SQL 命令或存储过程。不同的数据提供程序有不同的 Command 类,例如 SqlCommand (SQL Server), OracleCommand (Oracle), MySqlCommand (MySQL)。
代码示例 (SQL Server):
using System.Data.SqlClient; string connectionString = "Data Source=.;Initial Catalog=MyDatabase;Integrated Security=True"; using (SqlConnection connection = new SqlConnection(connectionString)) { string sql = "SELECT * FROM Products WHERE CategoryID = @CategoryID"; // 使用参数化查询 SqlCommand command = new SqlCommand(sql, connection); command.Parameters.AddWithValue("@CategoryID", 1); // 添加参数 try { connection.Open(); SqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { Console.WriteLine($"Product Name: {reader["ProductName"]}, Price: {reader["Price"]}"); } reader.Close(); } catch (Exception ex) { Console.WriteLine("Error executing command: " + ex.Message); } }
代码解释:
using (SqlConnection connection = new SqlConnection(connectionString)): 使用 using 语句可以确保 connection 对象在使用完毕后自动释放资源,即使发生异常。
string sql = "SELECT * FROM Products WHERE CategoryID = @CategoryID";: 定义 SQL 查询语句,使用参数 @CategoryID。
SqlCommand command = new SqlCommand(sql, connection);: 创建 SqlCommand 对象,关联 SQL 语句和连接对象。
command.Parameters.AddWithValue("@CategoryID", 1);: 添加参数,防止 SQL 注入。
command.ExecuteReader();: 执行查询,返回 SqlDataReader 对象。
DataReader 对象提供了一种快速、只读、只进的方式来从数据源读取数据。它一次读取一行数据,效率很高。不同的数据提供程序有不同的 DataReader 类,例如 SqlDataReader (SQL Server), OracleDataReader (Oracle), MySqlDataReader (MySQL)。
代码示例 (SQL Server):
(上述 Command 对象示例中已经包含了 DataReader 的使用)
代码解释:
SqlDataReader reader = command.ExecuteReader();: 执行查询,返回 SqlDataReader 对象。
while (reader.Read()): 循环读取数据,reader.Read() 返回 true 如果还有数据,否则返回 false。
Console.WriteLine($"Product Name: {reader["ProductName"]}, Price: {reader["Price"]}");: 访问每一列的数据,使用列名或者索引。
reader.Close();: 关闭 DataReader 对象,释放资源。
DataAdapter 对象用于在 DataSet 和数据源之间传输数据。它可以执行 SELECT、INSERT、UPDATE 和 DELETE 命令,并将结果填充到 DataSet 中。不同的数据提供程序有不同的 DataAdapter 类,例如 SqlDataAdapter (SQL Server), OracleDataAdapter (Oracle), MySqlDataAdapter (MySQL)。
代码示例 (SQL Server):
using System.Data; using System.Data.SqlClient; string connectionString = "Data Source=.;Initial Catalog=MyDatabase;Integrated Security=True"; string sql = "SELECT * FROM Products"; SqlDataAdapter adapter = new SqlDataAdapter(sql, connectionString); DataSet dataSet = new DataSet(); try { adapter.Fill(dataSet, "Products"); // 填充 DataSet DataTable productsTable = dataSet.Tables["Products"]; foreach (DataRow row in productsTable.Rows) { Console.WriteLine($"Product Name: {row["ProductName"]}, Price: {row["Price"]}"); } } catch (Exception ex) { Console.WriteLine("Error filling DataSet: " + ex.Message); }
代码解释:
SqlDataAdapter adapter = new SqlDataAdapter(sql, connectionString);: 创建 SqlDataAdapter 对象,关联 SQL 语句和连接字符串。
DataSet dataSet = new DataSet();: 创建 DataSet 对象。
adapter.Fill(dataSet, "Products");: 执行查询,并将结果填充到 DataSet 中,创建一个名为 "Products" 的 DataTable。
DataTable productsTable = dataSet.Tables["Products"];: 获取 DataTable 对象。
foreach (DataRow row in productsTable.Rows): 循环遍历 DataTable 中的每一行。
Console.WriteLine($"Product Name: {row["ProductName"]}, Price: {row["Price"]}");: 访问每一列的数据,使用列名或者索引。
DataSet 对象是一个内存中的数据缓存,可以包含多个 DataTable 对象。DataTable 对象包含 DataColumn 和 DataRow,类似于数据库中的表。DataSet 允许在断开连接的环境中操作数据。
代码示例:
(上述 DataAdapter 对象示例中已经包含了 DataSet 的使用)
代码解释:
DataSet dataSet = new DataSet();: 创建 DataSet 对象。
adapter.Fill(dataSet, "Products");: 将数据填充到 DataSet 中。
DataTable productsTable = dataSet.Tables["Products"];: 获取 DataTable 对象。
foreach (DataRow row in productsTable.Rows): 循环遍历 DataTable 中的每一行。
Command 对象也可以用于执行存储过程。
代码示例 (SQL Server):
using System.Data; using System.Data.SqlClient; string connectionString = "Data Source=.;Initial Catalog=MyDatabase;Integrated Security=True"; using (SqlConnection connection = new SqlConnection(connectionString)) { SqlCommand command = new SqlCommand("GetProductsByCategory", connection); command.CommandType = CommandType.StoredProcedure; // 指定 CommandType 为 StoredProcedure command.Parameters.AddWithValue("@CategoryID", 1); // 添加参数 try { connection.Open(); SqlDataReader reader = command.ExecuteReader(); while (reader.Read()) { Console.WriteLine($"Product Name: {reader["ProductName"]}, Price: {reader["Price"]}"); } reader.Close(); } catch (Exception ex) { Console.WriteLine("Error executing stored procedure: " + ex.Message); } }
代码解释:
command.CommandType = CommandType.StoredProcedure;: 指定 CommandType 为 StoredProcedure,表示执行的是存储过程。
SqlCommand command = new SqlCommand("GetProductsByCategory", connection);: CommandText 设置为存储过程的名称。
其他代码与执行 SQL 查询类似。
ADO.NET 提供了事务处理的支持,允许将多个数据库操作作为一个原子单元执行。如果其中一个操作失败,则所有操作都会回滚,确保数据的一致性。
代码示例 (SQL Server):
using System.Data.SqlClient; string connectionString = "Data Source=.;Initial Catalog=MyDatabase;Integrated Security=True"; using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); SqlTransaction transaction = connection.BeginTransaction(); // 开始事务 try { SqlCommand command1 = new SqlCommand("UPDATE Accounts SET Balance = Balance - 100 WHERE AccountID = 1", connection, transaction); command1.ExecuteNonQuery(); SqlCommand command2 = new SqlCommand("UPDATE Accounts SET Balance = Balance + 100 WHERE AccountID = 2", connection, transaction); command2.ExecuteNonQuery(); transaction.Commit(); // 提交事务 Console.WriteLine("Transaction committed successfully."); } catch (Exception ex) { transaction.Rollback(); // 回滚事务 Console.WriteLine("Transaction rolled back: " + ex.Message); } }
代码解释:
SqlTransaction transaction = connection.BeginTransaction();: 开始事务。
SqlCommand command1 = new SqlCommand("...", connection, transaction);: 创建 Command 对象,并将 transaction 对象传递给它。
transaction.Commit();: 提交事务,将所有更改永久保存到数据库。
transaction.Rollback();: 回滚事务,撤销所有更改。
ADO.NET 提供了丰富的功能,用于访问和操作数据。理解 Connection、Command、DataReader、DataAdapter 和 DataSet 这些核心对象,以及如何使用它们来执行查询、更新数据和处理事务,是使用 ADO.NET 的关键。 通过选择合适的数据提供程序,你可以连接到各种不同的数据源,并在 .NET 应用程序中使用它们。 记住始终在使用完毕后关闭连接和释放资源,以确保应用程序的性能和稳定性。 此外,使用参数化查询可以有效地防止 SQL 注入攻击,提高应用程序的安全性。