1. 程式人生 > >VC++使用ADO開發ACCESS資料庫

VC++使用ADO開發ACCESS資料庫

VC++使用ADO開發ACCESS資料庫

ADO和ADOX到底是什麼,二者的作用和區別

ADOMicrosoft 最新推出的資料庫訪問的高層軟體介面。它和Microsoft以前的資料庫訪問介面DAORDO相比具有更大的靈活性,使用也更方便,開發效率大為提高。

ADOX是核心ADO物件的擴充套件庫。它提供的附加物件可用於建立、修改和刪除模式物件,如表和過程。要使用ADOX,則應建立對ADOX型別庫的引用。ADOX庫檔名為Msadox.dll

通俗地講,ADO是訪問資料庫的一種介面,可以使用它方便地進行資料庫程式設計。而ADOX是微軟對ADO功能的擴充套件,比如:可以ADOX

建立資料庫(而ADO沒有建立資料庫的功能)。

ADOX建立ACCESS資料庫

ADOX建立access資料庫方法很簡單,只需要建立一個Catalog物件,然後呼叫它的Create方法就可以了。

例程ADOXCreateDatabase演示如何使用ADOX建立一個ACCESS資料庫。

開啟VC++ 6.0,新建一個基於對話方塊的工程ADOXCreateDatabase。在對話方塊IDD_ADOXCREATEDATABASE_DIALOG中新增一個編輯框IDC_DBNAME和一個按鈕IDC_BTN_CREATE,編輯框用以輸入資料庫名稱。

使用ClassWizard給編輯框建立一個

CString變數m_dbName

雙擊IDC_BTN_CREATE按鈕,並編輯OnBtnCreate()函式如下:

void CADOXCreateDatabaseDlg::OnBtnCreate()

{

       //使輸入到編輯框IDC_DBNAME的內容更新到m_dbName變數中

    UpdateData(TRUE);

    CString str;

       str="d:\\"+m_dbName+".mdb";

       //檢查該資料庫是否已經存在,如果該資料庫已經存在,彈出訊息框,返回

       //使用API函式PathFileExists()檢查路徑檔案是否存在

       //請注意:為了使用API函式PathFileExists(),需要加入

       //#include "Shlwapi.h"

    //#pragma comment(lib,"shlwapi.lib")

       if(PathFileExists(str))

       {

              CString strTemp;

              strTemp.Format("%s已存在!",str);

              AfxMessageBox(strTemp);

              return ;

       }

       //定義ADOX物件指標並初始化為NULL

       //ADOX建立access資料庫方法很簡單,

       //只需要新建一個Catalog物件,然後呼叫它的Create方法就可以了。

       //Catalog ADOX 的一個物件,它包含描述資料來源模式目錄的集合。

       //在這裡,您只需知道建立資料庫時使用這個物件就可以了。

       //注意用try...catch組合捕捉錯誤

       _CatalogPtr m_pCatalog = NULL;

       CString DBName="Provider=Microsoft.JET.OLEDB.4.0;Data source=";

    DBName=DBName+str;

       try

       {

              m_pCatalog.CreateInstance(__uuidof(Catalog));

              m_pCatalog->Create(_bstr_t((LPCTSTR)DBName));

       }

       catch(_com_error &e)

       {

              AfxMessageBox(e.ErrorMessage());

              return ;

 

       }    

}

使用ADOX,需要引入ADOX的動態連結庫msadox.dll,即在stdafx.h中加入如下語句:

#import "C:\Program Files\Common Files\system\ado\msadox.dll" no_namespace rename("EOF","adoEOF")

另外,ADOX屬於COM物件,所以要在CADOXCreateDatabaseApp::InitInstance()函式中加入:

       if(!AfxOleInit())

       {

              AfxMessageBox("OLE初始化出錯!");

              return FALSE;

       }

初始化COM

編譯並執行該例程,對於編譯過程中彈出的4146號警告不要理會。在編輯框中輸入一個數據庫名稱,點選建立資料庫按鈕,該資料庫將在d盤根目錄下建立,再次輸入該資料庫名稱並點選建立資料庫按鈕,將彈出警告對話方塊。

VC中使用ADO的時候會得到4146號警告資訊,我們可以不去理會,也可以通過#pragma warning指令解決,方法為在stdafx.h中加入的語句:

#import "C:\Program Files\Common Files\system\ado\msadox.dll" no_namespace rename("EOF","adoEOF")

前後再加一條語句,修改後為:

#pragma warning (disable:4146)

#import "C:\Program Files\Common Files\system\ado\msadox.dll" no_namespace rename("EOF","adoEOF")

#pragma warning (default:4146)

指令#pragma warning (disable:4146) 暫時遮蔽編譯時4146警告資訊

指令#pragma warning (default:4146) 重置編譯器的4146警告到預設狀態

ADO建立ACCESS資料庫的表

我們一般用ADOX建立資料庫,然後再用ADO建立資料庫的表。

例程CREATE_DB_AND_TABLE演示如何使用ADO建立ACCESS資料庫的表。

開啟VC++ 6.0,新建一個基於對話方塊的工程CREATE_DB_AND_TABLE。在對話方塊IDD_CREATE_DB_AND_TABLE_DIALOG中新增如下控制元件:

控制元件名稱

ID

用途

編輯框

IDC_DBNAME

輸入資料庫名稱

按鈕

IDC_BTN_CREATE

建立資料庫

編輯框

IDC_TABLENAME

輸入表名

按鈕

IDC_BTN_CREATE_TABLE

建立表

使用ClassWizard給兩個編輯框建立CString變數:

編輯框

CString變數

編輯框IDC_DBNAME

m_dbName

編輯框IDC_TABLENAME

m_tableName

雙擊IDC_BTN_CREATE按鈕,並編輯OnBtnCreate()函式如下:

void CADOXCreateDatabaseDlg::OnBtnCreate()

{

    UpdateData(TRUE);

    CString str;

       str="d:\\"+m_dbName+".mdb";

       if(PathFileExists(str))

       {

              CString strTemp;

              strTemp.Format("%s已存在!",str);

              AfxMessageBox(strTemp);

              return ;

       }

       _CatalogPtr m_pCatalog = NULL;

       CString DBName="Provider=Microsoft.JET.OLEDB.4.0;Data source=";

    DBName=DBName+str;

       try

       {

              m_pCatalog.CreateInstance(__uuidof(Catalog));

              m_pCatalog->Create(_bstr_t((LPCTSTR)DBName));

       }

       catch(_com_error &e)

       {

              AfxMessageBox(e.ErrorMessage());

              return ;

       }    

}

以上程式碼例程ADOXCreateDatabase中已經詳細敘述。

雙擊IDC_BTN_CREATE_TABLE按鈕,並編輯OnBtnCreateTable()函式如下:

void CCREATE_DB_AND_TABLEDlg::OnBtnCreateTable()

{

       //先判斷表名編輯框是否為空

       UpdateData(TRUE);

       if(!m_tableName.IsEmpty())

       {

              ADOX::_CatalogPtr m_pCatalog=NULL;

           ADOX::_TablePtr m_pTable=NULL;

        CString str;

          str="d:\\"+m_dbName+".mdb";

          CString DBName="Provider=Microsoft.JET.OLEDB.4.0;Data source=";

        DBName=DBName+str;

        //這段程式碼先檢查表是否已經存在,如果表已經存在,不再建立,直接返回。

        //其實這段程式碼不必深入研究,只需知道它的功能,直接拿來使用即可

          try

              {

                 m_pCatalog.CreateInstance(__uuidof(ADOX::Catalog));

                 m_pCatalog->PutActiveConnection(_bstr_t(DBName));

                 int tableCount=m_pCatalog->Tables->Count;

                 int i=0;

                 while(i<tableCount)

                     {

                        m_pTable=(ADOX::_TablePtr)m_pCatalog->Tables->GetItem((long)i);

                        CString tableName=(BSTR)m_pTable->Name;

                        if(tableName==m_tableName)

                            {

                               AfxMessageBox("該表已經存在!");

                               return;

                            }

                        i++;

                     }

              }

          catch(_com_error &e)

              {

                 AfxMessageBox(e.Description());

                 return;

              }

          ADODB::_ConnectionPtr m_pConnection;

          //建立表

          _variant_t RecordsAffected;

          try

              {

                     m_pConnection.CreateInstance(__uuidof(ADODB::Connection));

                     //Open方法的原型:

                     //Open(_bstr_t ConnectionString,_bstr_t UserID,_bstr_t Password,long Options)

                     //ConnectionString為連線字串,UserID是使用者名稱,Password是登陸密碼

                     //Options是連線選項,可以是如下幾個常量:

                     //adModeUnknown 預設,當前的許可權未設定

                     //adModeRead 只讀

                     //adModeWrite 只寫

                     //adModeReadWrite 可以讀寫

                     //adModeShareDenyRead 阻止其它Connection物件以讀許可權開啟連線

                     //adModeShareDenyWrite 阻止其它Connection物件以寫許可權開啟連線

                     //adModeShareExclusive 阻止其它Connection物件開啟連線

                     //adModeShareDenyNone 阻止其它程式或物件以任何許可權建立連線

                     m_pConnection->Open(_bstr_t(DBName),"","",ADODB::adModeUnknown);

              }

          catch(_com_error e)

              {

                 CString errormessage;

                 errormessage.Format("連線資料庫失敗!\r錯誤資訊:%s",e.ErrorMessage());

                 AfxMessageBox(errormessage);

                 return;

              }

          try

              {

                 CString strCommand;

            /* 執行SQL命令:CREATE TABLE建立表格 該表包含三個欄位:記錄編號 INTEGER,姓名 TEXT,出生年月 DATETIME    SQL語言中的create table語句被用來建立新的資料庫表格。

                     create table語句的使用格式如下:

                     create tablename (column1 data type,column2 data type,column3 data type);

                     如果使用者希望在建立新表格時規定列的限制條件,可以使用可選的條件選項

                     create table tablename

                         (column1 data type[constraint],

                            column2 data type[constraint],

                            column3 data type[constraint]);

             

            舉例:

                     create table employee

                     (firstname varchar(15),

                     lastname varchar(20),

                     age number(3),

                     address varchar(30),

                     city varchar(20));

                     簡單來說,建立新表格時,在關鍵詞create table後面加入所要建立的表格的名稱,然後在括號內順次設定各列的名稱,資料型別,以及可選的限定條件等。

                     使用SQL語句建立的資料庫表格和表格中列的名稱必須以字母開頭,後面可以使用字母,數字或下劃線,名稱的長度不能超過30個字元,注意,使用者在選擇表格名稱時不要使用SQL語言中的保留關鍵字,如select,create,insert等,作為表格或列的名稱。

               */

                 strCommand.Format("CREATE TABLE %s(記錄編號 INTEGER,姓名 TEXT,出生年月 DATETIME)",m_tableName);

                 //Execute(_bstr_t CommandText,VARIANT* RecordsAffected,long Options)

                 //其中CommandText是命令字串,通常是SQL命令,

                 //引數RecordsAffected是操作完成後所影響的行數

                 //引數Options表示CommandText中內容的型別,可以取下列值之一:

                 //adCmdText 表明CommandText是文字命令

                 //adCmdTable 表明CommandText是一個表名

                 //adCmdProc 表明CommandText是一個儲存過程

                 //adCmdUnknown 未知

                     m_pConnection->Execute(_bstr_t(strCommand),&RecordsAffected,ADODB::adCmdText);

                 if(m_pConnection->State)

                        m_pConnection->Close();

              }

          catch(_com_error &e)

              {

                 AfxMessageBox(e.Description());

              }

       }

}

這段程式碼先用ADOXCatalog物件檢查表是否已經存在,如果該表已經存在,直接返回;如果還沒有該表,使用ADOConnection物件的Execute函式建立表。

Connection物件的用法:首先定義一個Connection型別的指標,然後呼叫CreateInstance()來建立一個連線物件的例項,再呼叫Open函式建立與資料來源的連線。最後使用Execute()函式執行SQL語句建立表。

關於呼叫CreateInstance()來建立連線物件的例項,還需作一點說明。ADO庫包含三個基本介面:_ConnectionPtr介面,_RecordsetPtr介面和_CommandPtr介面。其分別對應Connection物件(完成應用程式對資料來源的訪問連線),Recordset物件(將查詢的結果以記錄集的方式儲存)和Command物件(對已連線的資料來源進行命令操作)。

_ConnectionPtr m_pConnection;

_RecordsetPtr m_pRecordset;

_CommandPtr m_pCommand;

而這三個物件例項的建立,可以使用如下語句:

m_pConnection.CreateInstance(__uuidof(Connection));

或者:

m_pConnection.CreateInstance(“ADODB.Connection”);

m_pRecordset.CreateInstance(__uuidof(Recordset));

或者:

m_pRecordset.CreateInstance(“ADODB.Recordset”);

m_pCommand.CreateInstance(__uuidof(Command));

或者:

m_pCommand.CreateInstance(“ADODB.Command”);

兩種方法的作用完全相同,使用哪種方法,完全是您的個人愛好問題。

如例程ADOXCreateDatabase,在BOOL CCREATE_DB_AND_TABLEApp::InitInstance()函式中加入:

       if(!AfxOleInit())

       {

              AfxMessageBox("OLE初始化出錯!");

              return FALSE;

       }

stdafx.h中加入如下語句:

#import "C:\Program Files\Common Files\system\ado\msadox.dll"

#import "C:\Program Files\Common Files\system\ado\msado15.dll" rename("EOF","adoEOF")

關於這兩條語句,需要進行特別說明:

由於該例程同時使用ADOXADO,需要同時引入msado15.dllmsadox.dll兩個庫。這兩個庫的名字空間是不同的,msado15.dll的名字空間是ADODBmsadox.dll的名字空間是ADOX。在使用ADO所屬的名字空間的變數,函式時,在前面加上ADODB::,在使用ADOX所屬的名字空間的變數,函式時,在前面加上ADOX::

另外,一般ADOXADO分開操作。您也可以在ADOX操作部分使用using namespace ADOX::,而在ADO操作部分使用using namespace ADO:,以區分名字空間。這樣,您就不必再使用ADOX::ADODB::了。

rename(“EOF”,”adoEOF”) //重新命名EOF是必要的,因為典型的VC應用都已經定義了EOF作為常數-1,為了避免衝突,將ADO中的EOF重新命名為adoEOF

#import中有一個屬性為no_namespace,這是告訴編譯器該類不在一個單獨的名字空間中,使用no_namespace意味著你不需要在初始化變數的時候引用名字空間。當然如果在您的應用中需要匯入多個型別庫的話,不要使用no_namespace,以免引起名字衝突。

再通俗一點講,就是隻匯入一個型別庫的話,可以在#import語句中加入no_namespace屬性,您的程式可以直接使用這個型別庫的名字空間的內容,而不必使用using namespace XXX;XXX::,這是因為no_namespace屬性告訴編譯器該型別庫不再名字空間,而是在全域性空間上工作;如果您匯入幾個型別庫,而這幾個型別庫之間沒有定義衝突,您也可以在使用no_namespace屬性;但如果兩個型別庫中有定義衝突,就不能使用no_namespace屬性,如果使用no_namespace屬性,就會在全域性空間產生定義衝突。

對於本例程,您可以把stdafx.h中的

#import "C:\Program Files\Common Files\system\ado\msadox.dll"

#import "C:\Program Files\Common Files\system\ado\msado15.dll" rename("EOF","adoEOF")

改為

#import "C:\Program Files\Common Files\system\ado\msadox.dll"

#import "C:\Program Files\Common Files\system\ado\msado15.dll" no_namespace  rename("EOF","adoEOF")

這樣改動後,void CCREATE_DB_AND_TABLEDlg::OnBtnCreateTable()中的ADODB::需要完全省略掉。

當然,您也可以把這兩行改為:

#import "C:\Program Files\Common Files\system\ado\msadox.dll" no_namespace

#import "C:\Program Files\Common Files\system\ado\msado15.dll" rename("EOF","adoEOF")

但這樣改動後,void CCREATE_DB_AND_TABLEDlg::OnBtnCreateTable()中的ADOX::需要完全省略掉。

由於ADOXADO有定義衝突,也就是說,msado15.dllmsadox.dll有相同的定義部分,所以在一個程式中,不允許同時使用no_namespace

使用_ConnectionPtr介面開發ACCESS資料庫

ADO中最重要的物件有三個:ConnectionRecordsetCommand,分別表示連線物件、記錄集物件和命令物件。三個物件對應的智慧指標分別是:_ConnectionPtr_RecordsetPtr_CommandPtrADO使用_ConnectionPtr這個指標來操縱Connection物件,類似地,後面用到的_CommandPtr_RecordsetPtr分別表示命令物件指標和記錄集物件指標。

Connection物件是這三個物件的基礎,它的主要作用是建立與資料庫的連線,建立了與資料庫的連線後,才能進行其它有關資料庫的訪問和操作。

也就是說,使用ADO操作資料庫,通常先用Connection物件的Open方法開啟一個庫連線,然後才能進行資料庫的操作。操作完成後,要關閉這個庫連線。

本文只講述Connection物件最常用的Open方法和Execute方法。Open方法用於開啟一個庫連線,而Execute方法一般用於執行一條SQL語句。

_ConnectionPtr智慧指標的用法:

首先定義一個Connection型別的指標,然後呼叫CreateInstance()來建立一個連線物件的例項,再呼叫Open函式建立與資料來源的連線。在建立連線物件後,可以使用連線物件的Execute()函式來執行SQL命令。

_ConnectionPtr智慧指標Open方法的原型:

              Open(_bstr_t ConnectionString,_bstr_t UserID,_bstr_t Password,long Options)

              ConnectionString為連線字串,UserID是使用者名稱,Password是登陸密碼

              Options是連線選項,可以是如下幾個常量:

              adModeUnknown 預設,當前的許可權未設定

              adModeRead 只讀

              adModeWrite 只寫

              adModeReadWrite 可以讀寫

              adModeShareDenyRead 阻止其它Connection物件以讀許可權開啟連線

              adModeShareDenyWrite 阻止其它Connection物件以寫許可權開啟連線

              adModeShareExclusive 阻止其它Connection物件開啟連線

              adModeShareDenyNone 阻止其它程式或物件以任何許可權建立連線

_ConnectionPtr智慧指標Execute方法的原型:

_RecordsetPtr Connection15::Execute(_bstr_t CommandText,VARIANT* RecordsAffected,long Options)

    其中CommandText是命令字串,通常是SQL命令,

    引數RecordsAffected是操作完成後所影響的行數

    引數Options表示CommandText中內容的型別,可以取下列值之一:

          adCmdText 表明CommandText是文字命令

          adCmdTable 表明CommandText是一個表名

          adCmdProc 表明CommandText是一個儲存過程

          adCmdUnknown 未知

Execute執行完後返回一個指向記錄集的指標。

例程CREATE_DB_AND_TABLE中已經使用了_ConnectionPtr指標的Open方法和Execute方法,在後面的例程我們將進一步詳細說明。

我們先講解幾條最常用的SQL語句。

SELECT查詢語句

我們希望用各種不同的方法來檢視和分析資料,SELECT語句就是我們要使用的語句,用於有選擇的從資料庫返回我們需要的資料,也就是查詢。

最基本的SELECT語句僅有兩個部分:要返回的列和這些列源於的表

為了便於講解演示,我們使用如下Northwind 示例資料庫中的 Employees

EmployeeID

FirstName

LastName

HireDate

City

Country

1

Nancy

Davolio

1/5/1992 12:00:00

Seattle

USA

2

Andrew

Fuller

14/8/1992 12:00:00

Tacoma

USA

3

Janet

Leverling

1/4/1992 12:00:00

Kirkland

USA

4

Margaret

Peacock

3/5/1993 12:00:00

Redmond

USA

5

Steven

Buchanan

17/10/1993 12:00:00

London

UK

6

Michael

Suyama

17/10/1993 12:00:00

London

UK

7

Robert

King

2/1/1994 12:00:00

London

UK

8

Laura

Callahan

5/3/1994 12:00:00

Seattle

USA

9

Anne

Dodsworth

15/11/1994 12:00:00

London

UK

如果我們希望檢索Employees表中所有客戶的所有資訊,我們可以使用星號(*)來簡單地表示所有列,查詢語句如下所示:

SELECT * FROM Employees

如果我們只需要特定列,我們應該在逗號分隔的列表中顯式指定這些列,如下所示:

SELECT EmployeeID, FirstNameLastNameHireDate FROM Employees

結果會顯示該表中所有行的指定欄位的資料。

顯式指定所需欄位還允許我們控制欄位返回的順序,如果我們希望LastName顯示在FirstName之前,我們可以編寫以下語句:

SELECT EmployeeID, LastNameFirstNameHireDate FROM Employees

WHERE子句

接下來我們要做的是開始限制或篩選從資料庫提取的資料。通過向SELECT語句新增WHERE子句,我們可以新增一個(或多個)條件,所選資料必須滿足這些條件,這將限制答覆查詢的行數也就是被提取的行數。

我們可以在上一個查詢的基礎上,將其限制為CityLondon的員工

SELECT EmployeeID, FirstName, LastName, HireDate, City FROM Employees

WHERE City = 'London'

查詢結果如下:

EmployeeID

FirstName

LastName

HireDate

City

5

Steven

Buchanan

17/10/1993 12:00:00

London

6

Michael

Suyama

17/10/1993 12:00:00

London

7

Robert

King

2/1/1994 12:00:00

London

9

Anne

Dodsworth