ADO.NET 是在用于直接满足用户开发可伸缩应用程序需求的 ADO 数据访问模型的基础上发展而来的。它是专门为 Web 设计的,并且考虑了伸缩性,无状态性和 XML 的问题。
ADO.NET 使用了某些 ADO 的对象,如 Connection 和 Command 对象,并且还引入了新的对象。主要的新 ADO.NET 对象包括 DataSet、DataReader 和 DataAdapter。
ADO.NET 这一发展版本与以前的数据结构之间的重要区别就是 DataSet 对象的存在,该对象独立于任何数据存储区并且与之不同。正因为如此,DataSet 对象作为一个独立实体运行。可以将数据集 (DataSet) 设想为始终断开的记录集,它对其所包含的数据的源或目标一无所知。DataSet 的里面很像数据库,有表、列、关系、约束、视图,等等。
DataAdapter 连接到数据库以填充 DataSet 的对象。然后,它又连接回数据库,根据 DataSet 保留数据时所执行的操作来更新数据库中的该数据。在过去,数据处理主要是基于连接的。现在,为了使多层应用程序更为高效,数据处理正转向基于消息的方式,围绕信息块进行处理。这种方式的中心是 DataAdapter,它起着桥梁的作用,在 DataSet 和其源数据存储区之间进行数据检索和保存。这一操作是通过请求对数据存储区进行适当的 SQL 命令来完成的。
基于 XML 的 DataSet 对象提供一致的编程模型,该模型可配合所有的数据存储模型使用,无论是单层的、关系型的、还是分层的。为做到这一点,DataSet 对象对其数据源“一无所知”,并且将它拥有的数据表示为集合和数据类型。无论 DataSet 中数据的源是什么,它都是通过由 DataSet 与其从属对象所公开的同一套标准 API 来操纵的。
虽然 DataSet 对其数据的源一无所知,但托管提供程序具有详细而具体的信息。托管提供程序的作用是在 DataSet 与数据存储区之间来回进行连接、填充和保持同步。OLE DB 数据提供者与 SQL Server .NET 数据提供者(System.Data.OleDb 和 System.Data.SqlClient)是 .Net 框架的一部分,它们提供四个基本对象:Command、Connection、DataReader 和 DataAdapter。在本文档的余下部分,我们将介绍 DataSet 和 OLE DB/SQL Server .NET 数据提供程序的每一部分,解释它们是什么以及如何对它们进行编程。
- Connection。用于连接到数据库和管理对数据库的事务。
- Command。用于对数据库发出 SQL 命令。
- DataReader。用于从 SQL Server 数据源读取只进数据记录流。
- DataSet。用于对单层数据、XML 数据和关系数据进行存储、远程处理和编程。
- DataAdapter。用于将数据推入 DataSet,并使数据与数据库保持一致。
注意 当处理到数据库的连接时,有两个不同的选项:SQL Server .NET 数据提供程序 (System.Data.SqlClient) 和 OLE DB .NET 数据提供程序 (System.Data.OleDb)。在这些示例中,我们将使用 SQL Server .NET 数据提供程序。这些示例的是为了直接与 Microsoft SQL Server 交互。OLE DB .NET 数据提供程序则用于与任何 OLE DB 提供程序交互(因为它在底层使用 OLE DB)。
Connection(连接)
连接用于与数据库“对话”,并由 SQLConnection 等特定于提供程序的类来表示。命令 (Command) 将遍历连接并以流的形式返回结果集,该结果集可由 DataReader 对象读取,或是被推入 DataSet 对象。
SqlConnection mySqlConnection = new SqlConnection("server=(local)\\NetSDK;Trusted_Connection=yes;database=northwind");
Command(命令)
命令包含向数据库提交的信息,并且由 SQLCommand 等特定于提供程序的类来表示。命令可以是存储过程调用、UPDATE 语句或返回结果的语句。还可将输入和输出参数、以及返回值用作命令语法的一部分。下面的示例说明如何对 Northwind 数据库发出 INSERT 语句。
SqlConnection myConnection = new SqlConnection("server=(local)\\NetSDK;Trusted_Connection=yes;database=northwind");
SqlCommand mySqlCommand = new SqlCommand("INSERT INTO Customers (CustomerId, CompanyName, ContactName, ContactTitle, Address) Values ('ABC','ABC Company', 'John Smith', 'Owner','One My Way')", myConnection);
SqlCommand mySqlCleanup = new SqlCommand("DELETE FROM Customers WHERE CustomerId = 'ABC'", myConnection);
DataReader
DataReader 对象对于数据有点像只读/只进游标。DataReader API 既支持平面数据,也支持分层数据。在对数据库执行命令之后返回一个 DataReader 对象。返回的 DataReader 对象的格式与记录集不同。例如,您可能会使用 DataReader 在 Web 页上显示搜索列表的结果。
mySqlConnection.Open();
myReader = mySqlCommand.ExecuteReader();
![](/Images/OutliningIndicators/None.gif)
Console.Write("客户 ID ");
Console.WriteLine("公司名称");
![](/Images/OutliningIndicators/None.gif)
while (myReader.Read())
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
Console.Write(myReader["CustomerId"].ToString() + " ");
Console.WriteLine(myReader["CompanyName"].ToString());
}
DataSet 和 DataAdapter
DataSet 对象与 ADO Recordset 对象相似,但功能更为强大,并具有另一重要区别:DataSet 始终是断开的。DataSet 对象表示数据的缓存,具有类似数据库的结构,如表、列、关系和约束。但是,尽管 DataSet 可以并且的确像数据库那样运行,但重要的是要记住:DataSet 对象不直接与数据或其他源数据进行交互。这使得开发人员能够使用始终保持一致的编程模型,而不用理会源数据的驻留位置。所有来自于数据库、XML 文件、代码或用户输入的数据都可添加到 DataSet 对象中。这样,由于对 DataSet 进行了更改,所以在更新源数据之前可以对这些更改进行跟踪和验证。DataSet 对象的 GetChanges 方法实际上是创建了另一个 DatSet,该 DatSet 只包含对数据做出的更改。然后,DataAdapter(或其他对象)使用此 DataSet 来更新原始的数据源。 DataSet 具有许多 XML 特性,包括生成和使用 XML 数据和 XML 架构的能力。XML 架构可以用来描述通过 WebServices 交换的架构。实际上,为了类型安全和语句结束,可以对带有架构的 DataSet 进行编译。
DataAdapter 对象在 DataSet 与源数据之间起到桥梁的作用。在使用 Microsoft SQL Server 数据库时,使用提供程序特定的 SqlDataAdapter(以及与其关联的 SqlCommand 和 SqlConnection)能够提高整体性能。对于其他支持 OLE DB 的数据库,将使用 OleDbDataAdapter 对象及其关联 OleDbCommand 和 OleDbConnection 对象。 在更改 DataSet 之后,DataAdapter 对象使用命令来更新数据源。使用 DataAdapter 的 Fill 方法调用 SELECT 命令;使用 Update 方法为每一发生更改的行调用 INSERT、UPDATE 或 DELETE 命令。可显式设置这些命令,以控制运行时用来解析更改的语句,包括对存储过程的使用。在特殊情况下,CommandBuilder 对象可以根据 Select 语句在运行时生成这些命令。但是,在运行时生成需要一个额外的服务器往返以收集元数据,所以在设计时显式提供 INSERT、UPDATE 和 DELETE 命令将会获得更佳的运行时性能。
SqlConnection myConnection = new SqlConnection("server=(local)\VSdotNET;Trusted_Connection=yes;database=northwind");
SqlDataAdapter mySqlDataAdapter = new SqlDataAdapter("select * from customers", myConnection);
![](/Images/OutliningIndicators/None.gif)
mySqlDataAdapter.InsertCommand.CommandText = "sp_InsertCustomer";
mySqlDataAdapter.InsertCommand.CommandType = CommandType.StoredProcedure;
mySqlDataAdapter.DeleteCommand.CommandText = "sp_DeleteCustomer";
mySqlDataAdapter.DeleteCommand.CommandType = CommandType.StoredProcedure;
mySqlDataAdapter.UpdateCommand.CommandText = "sp_UpdateCustomers";
mySqlDataAdapter.UpdateCommand.CommandType = CommandType.StoredProcedure;
mySqlDataAdapter.Update(myDataSet);
![](http://chs.gotdotnet.com/quickstart/howto/images/AdoDataSet.gif)
图:DataAdapter 和 DataSet
以下示例阐释了通过 SELECT 语句加载一个 DataAdapter。然后它在 DataSet 中更新、删除和添加一些记录。最后,通过 DataAdapter 将那些更新返回到源数据库。构造的 DeleteCommand、InsertCommand 和 UpdateCommand 将显示在页中。它还阐释了使用多个 DataAdapter 对象将多个表(Customers 和 Orders)加载到 DataSet中。
using System;
using System.Data;
using System.Data.SqlClient;
![](/Images/OutliningIndicators/None.gif)
public class adooverview4
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
{
public static void Main()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
adooverview4 myadooverview4 = new adooverview4();
myadooverview4.Run();
}
![](/Images/OutliningIndicators/InBlock.gif)
public void Run()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// Create a new Connection and SqlDataAdapter
![](/Images/OutliningIndicators/InBlock.gif)
SqlConnection myConnection = new SqlConnection("server=(local)\\NetSDK;Trusted_Connection=yes;database=northwind");
SqlDataAdapter mySqlDataAdapter = new SqlDataAdapter("Select * from Region", myConnection);
SqlParameter workParam = null;
![](/Images/OutliningIndicators/InBlock.gif)
// Restore database to it's original condition so sample will work correctly.
Cleanup();
![](/Images/OutliningIndicators/InBlock.gif)
// Build the insert Command
mySqlDataAdapter.InsertCommand = new SqlCommand("Insert into Region (RegionID, RegionDescription) VALUES (@RegionID, @RegionDescription)", myConnection);
![](/Images/OutliningIndicators/InBlock.gif)
workParam = mySqlDataAdapter.InsertCommand.Parameters.Add("@RegionID", SqlDbType.Int);
workParam.SourceColumn = "RegionID";
workParam.SourceVersion = DataRowVersion.Current;
![](/Images/OutliningIndicators/InBlock.gif)
workParam = mySqlDataAdapter.InsertCommand.Parameters.Add("@RegionDescription", SqlDbType.NChar, 50);
workParam.SourceVersion = DataRowVersion.Current;
workParam.SourceColumn = "RegionDescription";
![](/Images/OutliningIndicators/InBlock.gif)
// Build the update command
mySqlDataAdapter.UpdateCommand = new SqlCommand("Update Region Set RegionDescription = @RegionDescription WHERE RegionID = @RegionID" , myConnection);
![](/Images/OutliningIndicators/InBlock.gif)
workParam = mySqlDataAdapter.UpdateCommand.Parameters.Add("@RegionID", SqlDbType.Int);
workParam.SourceColumn = "RegionID";
workParam.SourceVersion = DataRowVersion.Original;
![](/Images/OutliningIndicators/InBlock.gif)
workParam = mySqlDataAdapter.UpdateCommand.Parameters.Add("@RegionDescription", SqlDbType.NChar, 50);
workParam.SourceVersion = DataRowVersion.Current;
workParam.SourceColumn = "RegionDescription";
![](/Images/OutliningIndicators/InBlock.gif)
DataSet myDataSet = new DataSet();
![](/Images/OutliningIndicators/InBlock.gif)
// Set the MissingSchemaAction property to AddWithKey because Fill will not cause primary key & unique key information to be retrieved unless AddWithKey is specified.
mySqlDataAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;
mySqlDataAdapter.Fill(myDataSet, "Region");
![](/Images/OutliningIndicators/InBlock.gif)
DataRow myDataRow1 = myDataSet.Tables["Region"].Rows.Find(2);
myDataRow1[1] = "已更改此地区说明";
![](/Images/OutliningIndicators/InBlock.gif)
DataRow myDataRow2 = myDataSet.Tables["Region"].NewRow();
myDataRow2[0] = 901;
myDataRow2[1] = "新地区";
myDataSet.Tables["Region"].Rows.Add(myDataRow2);
![](/Images/OutliningIndicators/InBlock.gif)
try
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
mySqlDataAdapter.Update(myDataSet, "Region");
Console.Write("已成功更新数据集!");
}
catch(Exception e)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.Write(e.ToString());
}
}
![](/Images/OutliningIndicators/InBlock.gif)
public void Cleanup()
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
SqlConnection myConnection = new SqlConnection("server=(local)\\NetSDK;Trusted_Connection=yes;database=northwind");
![](/Images/OutliningIndicators/InBlock.gif)
try
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
// Restore database to it's original condition so sample will work correctly.
myConnection.Open();
SqlCommand CleanupCommand = new SqlCommand("DELETE FROM Region WHERE RegionID = '901'", myConnection);
CleanupCommand.ExecuteNonQuery();
}
catch(Exception e)
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
Console.Write(e.ToString());
}
finally
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
myConnection.Close();
}
}
}
![](/Images/OutliningIndicators/None.gif)