浅析ADO.NET数据库编程技术 |
组成ADO.NET的各个类被包含在System.Data、System.Data.SqlClient以及System.Data.OleDb等三个名字空间中。我们可以将ADO.NET中的各个类分为两类:提供者类(Provider)和使用者类(Consumer)。提供者类完成将数据从数据源的读取和写入等实际操作,而当数据被读到存储介质后,我们就用使用者类完成数据的访问和操作等功能。所以用ADO.NET技术进行数据库访问的基本过程如下:首先,使用提供者类中的对象连接所要访问的数据库,将数据从该数据库中读到存储介质中,然后使用使用者类中的对象在非连接的模式下对数据进行相应的操作,操作完毕后,我们再使用提供者类中的对象将对数据的改动更新到数据库中。其中,提供者类中的对象包括了Connection对象、Command对象、CommandBuilder对象、DataReader对象和DataAdapter对象等。而使用者类中的对象则包括了DataSet对象、DataTable对象、DataColumn对象和DataRow对象等。下面我就依次对各个对象进行介绍。
顾名思义,Connection对象是用来连接所需的数据库的。ADO.NET提供三个完成数据库连接的类:SqlConnection类、OleDBConnection类和OdbcConnection类。其中SqlConnection类是专门为微软的SQL Server而设计的,OleDBConnection类是为其他的诸如MS Access、Oracle、DB2之类的数据库而设计的。
SqlConnection类以及相关的类包含在System.Data.SqlClient名字空间中。它们使用了一个托管的提供者,该提供者对SQL Server数据库的操作进行了很大程度的优化,所以在SQL Server数据库上的性能相当高,不过它只能用于SQL Server数据库而不能在其他类型的数据库中使用。而OleDBConnection类和相关的类包含在System.Data.OleDb名字空间中。它们能被应用于任何拥有一个能和.Net框架相兼容的Ole DB提供者的数据库。由于它们不是为专门的数据库设计的,而且是由托管的代码和非托管的代码组合而成的,所以运行的效率自然没有Sql类的效率高。不过正因为它们的通用性,你可以在不同类型的数据库之间相互转变而不用改写应用程序的代码,这正是它们设计的初衷。
在访问任何类型的数据库前必须先和相应的数据库取得连接,下面就给出两种不同的方法以供参考,第一种为OleDBConnection的方式,而第二种则是SqlConnection的方式。
第一种:
OleDBConnection myConnection = new OleDBConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;" + @"Data Source=C:\Test.MDB"); // 打开数据库连接 myConnection.Open(); |
第二种:
SqlConnection myConnection = new SqlConnection("Data Source=(local);" + "Integrated Security=SSPI;"+ "Initial Catalog=Test"); // 打开数据库连接 myConnection.Open(); |
我们使用该对象向数据源发送各种SQL查询之类的命令,同样根据前面所述,该对象分为两类:SqlCommand类的和OleDBCommand类的。下面是一个SELECT * FROM TABLE的例子,用SqlCommand类的对象实现,用OleDBCommand类的话方法类似,这里就不给出了。
SqlCommand myCommand = myConnection.CreateCommand(); myCommand.CommandText = "select count(*) as NumberOfRegions from region"; Int count = (int) myCommand.ExecuteScalar(); |
该对象是用来建立对数据进行修改的SQL命令的,同样该对象可分为两类:SqlCommandBuilder类的和OleDBCommandBuilder类的,下面是一个用OleDBCommandBuilder类的对象实现的例子,用SqlCommandBuilder类的对象的实现读者不妨按照例子自行推敲。
string strConn; strConn = "Provider=SQLOLEDB;Data Source=(local)\\NetSDK;" + "Initial Catalog=Northwind;Trusted_Connection=Yes;"; OleDbConnection cn = new OleDbConnection(strConn); OleDbCommand cmd = new OleDbCommand("CustOrdersOrders", cn); cmd.CommandType = CommandType.StoredProcedure; OleDbCommandBuilder cb = new OleDbCommandBuilder(); cn.Open(); cb.DeriveParameters(cmd); cn.Close(); foreach (OleDbParameter param in cmd.Parameters) { Console.WriteLine(param.ParameterName); Console.WriteLine("\t" + param.Direction.ToString()); Console.WriteLine("\t" + param.OleDbType.ToString()); Console.WriteLine(); } |
如果你想要快速的显示数据记录,那么最好使用SqlDataReader(为SQL Server数据库)或者OleDbDataReader(为其他类型的数据库)。它们每次从内存中读取一条记录,所以是显示数据记录最快的方法。但是,缺点就是不能对数据进行排序和过滤。因为使用这两种DataReader读记录时,是每次只读取一条记录,而不是将数据记录作为一个整体全部读出(如果你想在内存中产生一系列的数据记录,那么最好使用在后面介绍的DataSet了)。下面是一段参考代码(用OleDbDataReader实现):
// 创建一个为Microsoft Access OLE DB提供者的连接对象 OleDbConnection myConnection = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;" + @"Data Source=C:\Test.MDB"); // 打开数据库连接 myConnection.Open(); // 在此连接上创建SQL命令 OleDbCommand myCommand = myConnection.CreateCommand(); // 初始化SQL SELECT命令以接收数据 myCommand.CommandText = "SELECT Column1 FROM Table1"; // 在上面的SQL命令的基础上创建一个DataReader对象 OleDbDataReader myReader = myCommand.ExecuteReader(); // 不断读取Column1中的记录并显示在控制台中只到全部读完 while (myReader.Read()) { Console.WriteLine("{0}", myReader["Column1"]); } myReader.Close(); myConnection.Close(); |
该对象功能众多,它能完成对数据源的许多操作,比如更新已经被修改了的数据或是其他的操作。你可以根据不同的需求使用SqlDataAdapter类的对象或是OleDBDataAdapter类的对象。下面是一段实例代码:
OleDbConnection myConnection = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;" + @"Data Source=C:\Test.MDB"); myConnection.Open(); OleDbDataAdapter myAdapter = new OleDbDataAdapter("SELECT Column1 from Table1", myConnection); Console.WriteLine("{0}\n",myAdapter.SelectCommand.CommandText); OleDbCommandBuilder myBuilder = new OleDbCommandBuilder(myAdapter); OleDbCommand insertCommand = myBuilder.GetInsertCommand(); Console.WriteLine("{0}\n",insertCommand.CommandText); |
输出如下:
SELECT Column1 from Table1 INSERT INTO 'Column1' ('Column1') VALUES (?) |
介绍玩提供者类的各种对象,下面是使用者类的一些对象。
DataSet类包含在System.Data名字空间中,它是一个非常通用的类,几乎和任何类型的数据库都是相兼容的。它代表了一组被看作是一个单位的具有相关性的表。比如,在你的应用程序中,Table1、Table2和Table3也许是在同一个DataSet中的。通过这个对象你可以很快的从每个表中获取所需的数据,并在非连接的模式下对这些数据进行相应的修改,最后在以一种高效的操作方式把这些数据更新到数据库中。而且将DataSet对象和DataAdapter对象联合使用可以完成几乎所有的数据访问操作。请读者参考下面的例子以加深对该对象的印象:
// 创建一个DataAdapter对象以进行更新操作和其他的一些操作 SqlDataAdapter myAdapter = new SqlDataAdapter("SELECT * FROM Table1", myConnection); // 创建一个DataSet对象以包含相关的表、行和列 DataSet myDataSet = new DataSet(); // 对DataSet对象进行填充 myAdapter.Fill(myDataSet, "Table1"); // 显示变化以前的数据 Console.WriteLine("Record before change: {0}", myDataSet.Tables["Table1"].Rows[3]["Column1"]); // 对表1,行3,列1中的数据进行修改 myDataSet.Tables["Table1"].Rows[3]["Column1"] = "Hello"; // 显示变化以后的数据 Console.WriteLine("Record after change: {0}", myDataSet.Tables["Table1"].Rows[3]["Column1"]); // 调用Update命令以更新表中的变化 myAdapter.Update(myDataSet, "Table1"); |
这些对象相对比较简单,在这里就不多作介绍了。下面的代码显示了如何将一行新的内容添加到数据源中。
DataRow myRow = myDataSet.Tables["Table1"].NewRow(); myRow["Column1"] = "Hi"; myRow["Column2"] = "How do you do?"; myDataSet.Tables["Table1"].Rows.Add(myRow); myAdapter.Update(myDataSet, "Table1"); |