用ADO.Net實現通用數據庫編程

ADO.Net爲我們提供了一種全新的數據庫訪問機制,它使得數據庫編程變得相當容易。然而,在運用ADO.Net進行數據庫編程時,我們往往會因爲不注意某些細節問題而使得應用程序的可擴展性很差,也即某個數據庫應用程序只能應用於某個特定的數據庫,而不能和更多的其他類型的數據庫進行交互。本文我就向大家介紹如何運用ADO.Net中的接口(Interface)技術來實現通用的數據庫編程。

ADO.Net體系結構

在具體介紹如何實現通用數據庫編程前,我先向大家簡要的介紹一下ADO.Net的體系結構。ADO.Net是由一系列的數據庫相關類和接口組成的,它的基石是XML技術,所以通過ADO.Net我們不僅能訪問關係型數據庫中的數據,而且還能訪問層次化的XML數據。

ADO.Net爲我們提供了兩種數據訪問的模式:一種爲連接模式(Connected),另一種爲非連接模式(Disconnected)。運用過ADO技術的編程人員對前一種模式應該是非常熟悉的,而後一種模式則是ADO.Net中才具有的。相比於傳統的數據庫訪問模式,非連接的模式爲我們提供了更大的可升級性和靈活性。在該模式下,一旦應用程序從數據源中獲得所需的數據,它就斷開與原數據源的連接,並將獲得的數據以XML的形式存放在主存中。在應用程序處理完數據後,它再取得與原數據源的連接並完成數據的更新工作。

ADO.Net中的DataSet類是非連接模式的核心,數據集對象(DataSet)以XML的形式存放數據。我們既可以從一個數據庫中獲取一個數據集對象,也可以從一個XML數據流中獲取一個數據集對象。而從用戶的角度來看,數據源在哪裏並不重要,也是無需關心的。這樣一個統一的編程模型就可被運用於任何使用了數據集對象的應用程序。

在ADO.Net體系結構中還有一個非常重要的部分就是數據提供者對象(Data Provider),它是訪問數據庫的必備條件。通過它,我們可以產生相應的數據集對象;同時它還提供了連接模式下的數據庫訪問支持。

下面的圖就顯示了ADO.Net總體的體系結構。



圖1

數據提供者對象

本文介紹的是通用數據庫編程,所以要從數據提供者對象入手,使得一個應用程序具有訪問多個不同類型數據庫的能力。ADO.Net中的數據提供者對象包括了數據庫連接接口(IDbConnection)、數據庫命令接口(IDbCommand)、數據讀取器接口(IDataReader)和數據適配器接口(IDbDataAdapter)等不同種類的接口。通過這些接口,應用程序就可以訪問數據庫、執行相關的命令操作並獲取結果,獲取的結果可以是以XML數據的形式存放在數據集對象中,也可以是直接被應用程序所使用。ADO.Net中的數據提供者對象爲我們提供了以上一些接口,通過這些接口每個應用程序都可以有不同的實現方法以訪問特定類型的數據庫。

ADO.Net中的數據提供者對象很像OLE DB中的數據提供者對象,不過它們還是有區別的,前者實現了.Net的接口,而後者則實現了COM的接口。目前,ADO.Net中包括了兩種類型的數據提供者對象:一種爲OleDb數據提供者對象,它可以通過COM層和OLE DB進行交互;另一種爲SqlServer數據提供者對象,它是專門應用於MS SQL Server的,所以性能得到了優化。不過隨着時間的推移,會有更多的數據庫廠商提供專門的數據提供者對象以供大家使用的。和OleDb數據提供者對象相關的類都是以前綴OleDb命名的,而和SqlServer數據提供者對象相關的類則是以前綴Sql命名的。在實際的應用程序中,我們可以根據需要選擇相應類型的數據提供者對象。不過爲了使應用程序具有通用性,我們應儘量通過使用數據提供者對象的接口而並非某個特定類型的數據提供者對象來實現。

下面的表列舉了兩種類型的數據提供者對象中的各個並行類和相應的接口名稱。

表1

接口名稱 OleDb SQL Server
IDbConnection OleDbConnection SqlConnection
IDbCommand OleDbCommand SqlCommand
IDataReader OleDbDataReader SqlDataReader
IDbDataAdatpter OleDbDataAdapter SqlDataAdapter
IDbTransaction OleDbTransaction SqlTransaction
IDataParameter OleDbDataParameter SqlDataParameter



ADO.Net命名空間

.Net框架中和ADO.Net相關的命名空間包括了以下幾個:System.Data、System.Data.OleDb、System.Data.SqlClient、System.Data.SqlTypes以及System.Data.Common。其中System.Data中包含了組成ADO.Net體系結構的一些基本類;System.Data.OleDb中包含了運用OleDb類型的數據提供者對象的類;System.Data.SqlClient中則包含了運用SqlServer類型的數據提供者對象的類;System.Data.SqlTypes中包含了代表SQL Server中的數據類型的類;System.Data.Common中則包含了被所有的數據提供者對象所共享的類。

示例數據庫

通過以上一些對於ADO.Net的基本介紹,我想大家對ADO.Net至少有了個大概的瞭解。那麼如何具體運用ADO.Net中的數據提供者對象的接口技術來實現通用數據庫編程呢?下面我就通過一個實例向大家介紹具體的實現方法,該實例中運用了兩種類型的數據庫,一種爲Access版的,另一種爲SQL Server版的。相應地,前一種數據庫需要通過OleDb類型的數據提供者對象來訪問,而後一種的則需要通過SqlServer類型的數據提供者對象來訪問。我們的實例程序就是要通過運用ADO.Net數據提供者對象的接口技術來實現訪問兩種類型數據庫的功能。同時,我還會分別介紹在連接模式和非連接模式這兩種不同的數據庫訪問模式下的不同的實現方法。

實例中用到的示例數據庫爲一個小型銀行的帳號信息數據庫,其中包括了三個表,分別如下:

1.Account表:存儲了銀行的所有的帳號信息,包括了四個字段:AccountID、Owner、AccountType以及Balance,其中AccountID爲主鍵。

2.Transaction表:存儲了每個帳號的交易信息,包括了三個字段:XactType、AccountID和Amount,並且Account表和Transaction表構成了父子關係。

3.IdGen表:該表僅包括了一個字段:NextAccountID,而且只存儲了一行數據,其功能是用於產生一個新的帳號。

我們的示例數據庫包括了Access和SQL Server兩個不同類型的版本,你可以在源代碼文件中找到一個SimpleBank.mdb文件和一個CreateSimpleBank.sql文件,前者是Access版的數據庫文件,而後者是產生SQL Server版數據庫的腳本文件。

連接模式下的實現方法

儘管ADO.Net提倡使用非連接的數據庫訪問模式,但它還是提供了對連接模式訪問的支持。在本實例程序中,我就先向大家介紹在連接模式下的通用數據庫編程的實現方法。

1.運用數據庫連接接口

數據庫應用程序的必備步驟就是連接到相應的數據庫,我們的程序也不例外。對於不同類型的數據庫,我們可以分別運用OleDbConnection類的對象或是SqlConnection類的對象來實現數據庫的連接。這些類中包含了ConnectionString、ConnectionTimeout等屬性,還提供了Open、Close等方法。通過設置相應的屬性和運用某些方法我們就可以實現數據庫的連接功能。不過我們在這裏要運用的是IDbConnection接口的實現方法。在創建了某個類型的數據庫連接對象後,我們應獲取一個類型爲IDbConnection的接口引用,在以後的編程過程中,我們就應該使用該接口引用而非原先創建的那個特定類型的數據庫連接對象。

下面我先給出SQL Server版的實例程序,文章的後面還會給出Access版的實例程序的源代碼。在連接到數據庫一塊中,首先創建一個SqlConnection對象,然後將該對象傳遞給一個類型爲IDbConnection的接口引用,這樣該接口引用就能引用原對象了。下面的代碼顯示了程序一開始連接到SQL Server數據庫,然後進入一個命令循環的過程。其中代碼中爲粗體的部分是我們需要注意的,我們可以通過比較Access版實例程序中的相應代碼來理解通過運用接口技術實現通用數據庫編程的具體方法。


Module ConnectedSql
  Private connStr As String = _
   "server=localhost;uid=sa;pwd=;database=SimpleBank"
  Private conn As IDbConnection
  Dim sqlConn As New SqlConnection()
  Sub Main()
   OpenSql()
   CommandLoop()
  End Sub
  Private Sub OpenSql()
   conn = sqlConn
   conn.ConnectionString = connStr
   Console.WriteLine( _
     "Using SQL Server to access SimpleBank")
   Console.WriteLine( _
     "Database state: " & conn.State.ToString())
   conn.Open()
   Console.WriteLine(_ 
     "Database state: " & conn.State.ToString())
  End Sub


實例程序運行時,控制檯將顯示如下信息。


Using SQL Server to access SimpleBank
Database state: Closed
Database state: Open
Enter command, quit to exit
>

  

運用數據庫命令接口

在我們創建了數據庫連接對象的接口引用並完成與數據庫的連接之後,我們就可以創建一個數據庫命令對象來實現對數據庫的實際操作。同樣,數據庫命令對象包括了OleDbCommand類型的對象和SqlCommand類型的對象。不過在本實例程序中我們還是要將創建的對象傳遞給一個類型爲IDbCommand的接口引用,並在後面的程序中運用之。

接着上面的SQL Server版的實例程序,我們創建了一個SqlCommand類型的對象。


Private Function CreateCommand(ByVal query As String) _
As IDbCommand
  Return New SqlCommand(query, sqlConn)
End Function


這樣我們就可以將該對象傳遞給它的接口引用,並在以後的程序中一直使用該接口引用了。下面的函數實現了接口引用的ExcuteNonQuery操作,其返回的結果是該操作實際被影響到的記錄的數目。同時它還提供了ExcuteScalar、ExcuteReader和ExcuteXmlReader等不同的操作方法。


Private Sub RemoveAccount(ByVal id As Integer)
  Dim query As String = _
   "delete from Account where AccountId = " & id
  Dim command As IDbCommand = CreateCommand(query)
  Dim numrow As Integer = command.ExecuteNonQuery()
  Console.WriteLine("{0} rows updated", numrow)
End Sub


運用數據讀取器接口

如上面提到的那樣,我們在創建一個數據庫命令對象後可以通過執行ExcuteReader操作來獲取一個類型爲IDataReader的接口引用。通過該數據讀取器,我們就可以獲得一個只讀的而且只能向前讀的數據流。數據讀取器在處理大量記錄的時候是非常有效的,因爲任何時候它在主存中僅存儲了一條當前記錄,所以處理的效率是非常高的。在運用完一個數據讀取器之後,我們必須顯式的將其關閉,否則就得不到任何由它返回的參數或結果。數據讀取器擁有一個Item屬性,通過該屬性我們能訪問當前的記錄,它還具有一個Read方法,該方法的功能就是向前讀取數據,讀取成功返回true,否則爲false。

下面的函數運用了一個數據讀取器的接口引用,並在控制檯中顯示Account表中的各條記錄信息。


Private Sub ShowList()
  Dim query As String = "select * from Account"
  Dim command As IDbCommand = CreateCommand(query)
  Dim reader As IDataReader = command.ExecuteReader()
  While reader.Read()
   Console.WriteLine("{0} {1,-10} {2:C}", _
     reader("AccountId"), reader("Owner"), _
     reader("Balance"))
  End While
  reader.Close()
End Sub


Access版的實例程序

上面我給出了SQL Server版的實例程序的部分代碼,下面則是Access版的部分代碼(除去了命令循環的部分,該部分內容請參考源代碼文件中的源碼,其中SQL Server版的文件夾爲ConnectedSql,Access版的文件夾爲ConnectedJet)。通過比較代碼中爲粗體的那些部分,我相信你會很容易找到運用接口技術實現通用數據庫編程的方法的。


' ConnectedJet.vb
Imports System
Imports System.Data
Imports System.Data.OleDb
Module ConnectedJet
  Private connStr As String = _
   "Provider=Microsoft.Jet.OLEDB.4.0;" _
   & "Data Source=C:/OI/Databases/SimpleBank.mdb"
  Private conn As IDbConnection
  Dim jetConn As New OleDbConnection()
  Sub Main()
   OpenJet()
   CommandLoop()
  End Sub
  Private Sub OpenJet()
   conn = jetConn
   conn.ConnectionString = connStr
   Console.WriteLine("Using Access DB SimpleBank.mdb")
   Console.WriteLine("Database state: " & _
     conn.State.ToString())
   conn.Open()
   Console.WriteLine("Database state: " & _
     conn.State.ToString())
  End Sub
  Private Sub CommandLoop()
...
  Private Sub ShowList()
   Dim query As String = "select * from Account"
   Dim command As IDbCommand = CreateCommand(query)
   Dim reader As IDataReader = command.ExecuteReader()
   While reader.Read()
     Console.WriteLine("{0} {1,-10} {2:C}", _
      reader("AccountId"), reader("Owner"), _
      reader("Balance"))
   End While
   reader.Close()
  End Sub
  Private Sub AddAccount(ByVal bal As Decimal, _
  ByVal owner As String, ByVal id As Integer)
   Dim query As String = "insert into Account values(" _
    & id & ", '" & owner & "', ' ', " & bal & ")"
   Dim command As IDbCommand = CreateCommand(query)
   Dim numrow As Integer = command.ExecuteNonQuery()
   Console.WriteLine("{0} rows updated", numrow)
  End Sub
  Private Sub RemoveAccount(ByVal id As Integer)
   Dim query As String = _
     "delete from Account where AccountId = " & id
   Dim command As IDbCommand = CreateCommand(query)
   Dim numrow As Integer = command.ExecuteNonQuery()
   Console.WriteLine("{0} rows updated", numrow)
  End Sub
  Private Sub ChangeAccount(ByVal id As Integer, _
  ByVal owner As String)
   Dim query As String = _
     "update Account set Owner = '" _
     & owner & "' where AccountId = " & id
   Dim command As IDbCommand = CreateCommand(query)
   Dim numrow As Integer = command.ExecuteNonQuery()
   Console.WriteLine("{0} rows updated", numrow)
  End Sub
  Private Sub ClearAccounts()
   Dim query As String = "delete from Account"
   Dim command As IDbCommand = CreateCommand(query)
   Dim numrow As Integer = command.ExecuteNonQuery()
   Console.WriteLine("{0} rows updated", numrow)
  End Sub
  Private Function CreateCommand(ByVal query As String) _
  As IDbCommand
   Return New OleDbCommand(query, jetConn)
  End Function
End Module


非連接模式下的實現方法

1.運用數據集對象

一個數據集對象能以XML的形式將數據存放在主存中,對於任何類型的數據源,它都提供了一個統一的編程模型,這就大大減輕了編程人員的工作。一個數據集對象中包含了一系列的表以及表之間的關係。而每個表中又包含了其主鍵、外鍵、字段和約束等信息,這些綜合起來就決定了表的模式,表中還包含了一系列存儲表數據的記錄。

你可以運用以下一些方法產生一個數據集對象:

a. 運用一個數據適配器對象從一個數據庫中讀取模式和數據併產生數據集對象。

b. 動態創建模式並生成數據集對象。

c. 從XML數據源中獲取數據集對象。

用上面的第二種和第三種方法獲取的數據集對象本身就是數據庫無關的,而在運用第一種方法時,我們可以通過使用類型爲IDbDataAdapter的接口引用來達到通用數據庫編程的目的。

2.運用數據適配器接口

數據適配器在數據集對象和其數據源之間起了一個橋樑的作用。ADO.Net中同樣有兩種類型的數據適配器對象,一種爲OleDb類型的,另一種爲SqlServer類型的。前者的相應類爲OleDbDataAdapter,而後者的相應類自然爲SqlDataAdapter了。一個數據適配器包括了SelectCommand、InsertCommand、UpdateCommand以及DeleteCommand等屬性,通過從這些屬性的名稱我們不難知道其具體的作用。同時,一個數據適配器還包括了Fill和Update等方法。其中Fill方法能將模式和數據填充到數據集對象中,而Update方法則完成了數據更新的功能。

下面的函數就顯示瞭如何根據一個類型爲IDbDataAdapter的接口引用產生一個數據集對象的方法。


Private Sub FillDataSet()
	OpenDb()
	Dim query As String = "select * from Account"
	adapter = CreateAdapter(query)
	adapter.Fill(ds)
	CloseDb()
End Sub
Private Function CreateAdapter(ByVal query As String) As IDbDataAdapter
	Dim adapter As New SqlDataAdapter(query, connStr)
...
	Return adapter
End Function


同樣,我們的實例程序包括了兩個版本,你可以在源代碼文件中找到,其中SQL Server版的文件夾爲BankDbSql,Access版的文件夾爲BankDbJet。

總結

以上我向大家介紹了在ADO.Net中如何運用接口技術實現通用數據庫編程的方法,這項技術是非常有用的,而平常我們卻很容易將其忽視掉,這樣的結果就是應用程序的可升級性、靈活性和通用性大打折扣。所以希望大家能好好掌握這項技術,在實際運用中編寫出通用性很強的應用程序,以滿足更多的實際需要。
文章來自:http://www.uml.org.cn/net/net021.htm
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章