☛ DAO QueryDef 對象

QueryDef 對象表示 Access 資料庫中的已保存查詢。使用 VBA 代碼,可指向某個現有查詢中的一個 QueryDef 對象變量 ( 或者創建一個新查詢 ),並更改查詢的 SQL 語句,填充查詢使用的參數,然後執行該查詢。該查詢可能是返回記錄集的選擇查詢,也可能是修改查詢的基礎表中的代碼的動作查詢。

在代碼中創建 QueryDef 類似於創建 TableDef,只是新的 QueryDef 不必顯示追加到資料庫的 QueryDefs 集合。下面顯示的 CreateNewQueryDef 過程創建了一個新的 QueryDef,用於查詢 Customers 表中的記錄:

Public Sub CreateNewQueryDef()

    Dim daDb As DAO.Database
    Dim daQdf As DAO.QueryDef
  
    Const sQRYNAME As String = "MyQueryDef"
  
    Set daDb = CurrentDb
  
    On Error Resume Next
       daDb.QueryDefs.Delete sQRYNAME
    On Error GoTo 0
  
    Set daQdf = daDb.CreateQueryDef(sQRYNAME, _
        "SELECT * FROM tblCustomers;")
  
    daDb.Close
    Set daDb = Nothing
  
End Sub

實際上,執行 CreateNewQueryDef 方法後,Access 會立即將新的 QueryDef 添加到資料庫中。如果不希望 QueryDef 顯示在 ” 導航 ” 窗格中,必須顯式地將其刪除,如下所示:

CurrentDb.TableDefs.Delete "QueryDefName"

如有必要,可以創建一個沒有名稱的 QueryDef。這種情況下,不會保存新的 QueryDef ,並且它也不會顯示在 ” 導航 ” 窗格中。舉例來說,如果想使用數據填充某個組合框或列表框,但不希望創建永久性的 QueryDef ,因爲每次執行代碼時條件都會發生變化,此時,這種方法可能會非常有用。

一種傳統的高級 Access 技術是動態更改現有 QueryDef 對象的 SQL 語句。一旦 SQL 屬性發生更改,查詢便會返回新的 SQL 語句指定的記錄集,如下所示:

Public Sub ChangeQueryDefSQL()

    CurrentDb.QueryDefs("MyQueryDef").SQL = _
      "SELECT * FROM tblProducts;"
    
End Sub

注意,ChangeQueryDefSQL 過程並不聲明任何對象變量 ( 例如 daDb 或 daQdf ) 以引用 Database 或 QueryDef。相反,該過程將使用 CurrentDb 來引用 Database,並直接在 QueryDefs 屬性返回的對象上訪問 SQL 屬性。對於較長的過程,建議使用對象變量,但對於上面這種較短的過程,直接使用 CurrentDb 會更容易一些,並且可以實際改善可讀性。

直接從 QueryDef 填充 DAO Recordset 對象非常容易。注意該過程比等效的 ADO 過程簡單多少。

Public Function GetRecordset() As DAO.Recordset

    Dim daRs As DAO.Recordset
    Dim daQdf As DAO.QueryDef
  
    Set daQdf = CurrentDb.QueryDefs("MyQueryDef")
  
    'Open Recordset from QueryDef.
    Set daRs = daQdf.OpenRecordset(dbOpenSnapshot)
  
    daRs.MoveLast
    Debug.Print "Number of records = " & daRs.RecordCount
  
    Set GetRecordset = daRs

End Function

注意,局部聲明的 Recordset 對象 ( daRs ) 將在函數即將結束前指定給函數。通過這種方式,過程可以構建記錄集,而不必在應用程序需要記錄集的每個位置都重複用於設置記錄集和運行 QueryDef 的代碼。

☛ DAO Recordset 對象

Recordset 對象將被聲明並設置爲應用程序中的特定表、查詢或 ODBC 數據源。使用 Recordset 對象的方法,可以更新、編輯和刪除記錄,在記錄集中向前和向後移動,或使用 Find 和 Seek 法查找特定的記錄。

Recordset 對象可以是 Table、Dynaset 或 Snapshot 類型,指定的類型取決於你的需求。例如,假定你只是希望在表中掃描以搜索某個字段的特定值。這種情況下,Snapshot 可能是比較好的選擇,它是數據的只讀視圖。或者,你可能希望動態查詢某個表,但查詢取決於用戶輸入。這種情況下,你可能會基於輸入值構建一個 SQL 語句,並使用該 SQL 語句構建 Dynaset 類型的記錄集。

Dim daDb As DAO.Database
Dim daRs As DAO.Recordset
Dim sSql As String

sSql = "SELECT * FROM tblCustomers;"
Set daDb = CurrentDb
Set daRs = daDb.OpenRecordset(sSql, dbOpenSnapshot)

如果不是顯式選擇 Recordset 的類型,Access 將使用它認爲最高效的方法。你不能使用 dbOpenTable 選項打開 ODBC 數據源。而必須使用 dbOpenDynaset 和 dbOpenSnapshot 常量。

下面的示例中,直接針對 tbCustomers 創建記錄集,表中每一行中的每個字段都顯示在立即窗口中。

Public Sub OpenDAORecordset()

    Dim daDb As DAO.Database
    Dim daRs As DAO.Recordset
    Dim i As Long
  
    Set daDb = CurrentDb
  
    'Open recordset directly against a table:
    Set daRs = daDb.OpenRecordset("tblCustomers")
  
    Debug.Print "Table-type recordset: " & daRs.Name
      
    ' Enumerate records.
    Do While Not daRs.EOF
       For i = 0 To daRs.Fields.Count - 1
           Debug.Print daRs.Fields(i).Name & ": " & daRs.Fields(i).Value
       Next i
    
       Debug.Print
    
       daRs.MoveNext
    Loop
  
    daRs.Close
    Set daRs = Nothing
    Set daDb = Nothing
  
End Sub

 

☛ DAO Field 對象 ( 記錄集 )

記錄集中的 Field 對象表示某個表中的或某個查詢返回的一列數據。記錄集 Field 對象與其 TableDef 和 QueryDef 對等對象有所不同,主要體現在它們實際包含數據值。每個 TableDef 對象都包含一個 Fields 集合,其中保存 TableDef 表示的表中存儲的數據。

下面的代碼,運行後將會顯示 tblCustomers 中 Company 字段的所有 ” 有效 ” 屬性:

Public Sub DisplayFieldProperties()

    Dim daDb As DAO.Database
    Dim daTdf As DAO.TableDef
    Dim daFld As DAO.Field
    Dim daProp As DAO.Property
  
    Set daDb = CurrentDb
    Set daTdf = daDb.TableDefs("tblCustomers")
  
    Set daFld = daTdf.Fields("Company")
  
    Debug.Print "Properties in Company field:"
  
    For Each daProp In daFld.Properties
        On Error Resume Next
           Debug.Print Space(2) & daProp.Name & " = " & daProp.Value
        On Error GoTo 0
    Next daProp
  
    daDb.Close
  
End Sub

在某個特定時間,並不是與 Field 對象關聯的所有屬性都是有效的。某些屬性僅當欄位包含數據或當欄位包含在索引中時才會被設置。例如,Field 對象的 Value 屬性不能直接從代碼中引用。只能通過欄位在 Recordset 對象中的成員身份來設置或獲取該欄位的值。上面代碼中的 On Error Resume Next 語句允許該代碼運行,而不考慮無效屬性。在該代碼引用無效屬性時,可能發生的錯誤將被忽略。

☛ 在 ADO 和 DAO 之間的選擇

鑑於 ADO 與 DAO 非常相似,在決定爲新的 Access 應用程序選擇哪種語法時,可能會舉棋不定 ( 假設現有的 Access 應用程序已經指定 ADO 或 DAO )。畢竟,Microsoft 會繼續支持 ADO 和 DAO,並且針對更新的 Access 版本引入了 ACEDAO。那麼,那種最適合你的應用程序呢?

與資料庫開發中的其他任何對象一樣,答案取決於你的具體情況。如果不考慮更復雜的對象模型,DAO 對於執行某些任務速度上要稍微快一些,也更容易一些。由於 DAO 不需要連接字符串,因此,編寫 DAO 代碼應該比較簡單、容易。很多情況下,可以完全通過記憶編寫出成功的 DAO 過程,而不必通過參考書或網絡查找相應的語法。此外,DAO 還要比 ADO 更快一些,在處理小型數據集時尤其如此。

另一方面,在連接到外部資料庫 ( 不管數據源是另一個 Access 應用程序還是 SQL Server 資料庫 ) 時,非常適合 ADO。根據引用的提供程序,ADO 連接包括可以爲你提供連接狀態 ( 開放、正在連接、已斷開連接等 ) 的屬性。某些情況下,該信息可能會非常有價值。

在同一個應用程序中同時包含 ADO 和 DAO 代碼不會產生任何問題,但不能在同一個工程中使用 DAO 和 ACEDAO。不過,一定要根據所使用的對象語法,在對象引用中加上 DAO ( 或 ACEDAO ) 或 ADODB 前綴。

很多情況下,決定使用 DAO 或 ADO 取決於找到的在應用程序中使用的示例代碼。差不多有數千個使用 DAO 或 ADO 的 VBA 代碼示例。如果單從技術角度看,沒有特別充分的理由使用 DAO 或 ADO。唯一的例外情況是在使用 SQL Server 數據時。由於 Microsoft 爲 SQL Server 提供了一種本機 ADO 提供程序,因此,在使用 SQL Server 時,ADO 顯然是更好的選擇。與 SQL Server 資料庫建立連接後,ADO Command 對象是調用存儲過程或針對 SQL Server 表運行即席查詢的理想方式。在 SQL Server 上下文環境中,ADO 幾乎總是比 DAO 快,並且效率更高,因爲 DAO 對 SQL Server 的訪問僅限於使用指向 SQL Server 資料庫的 OLEDB 數據源。

這裏明確說明一下,ACEDAO 是 Access 2016 中默認數據訪問庫。創建的每個新 Access 2016 資料庫都設置了一個對已經存在的 Microsoft Office 15.0 Access Database Engine Object Library ( ACEDAO ) 的引用。如果想要在 Access 2016 應用程序中使用 ADO,必須手動添加對 Microsoft ActiveX Data Object 6.1 Library 的引用。