VC++使用ADO開發ACCESS資料庫
VC++使用ADO開發ACCESS資料庫
ADO和ADOX到底是什麼,二者的作用和區別
ADO是Microsoft 最新推出的資料庫訪問的高層軟體介面。它和Microsoft以前的資料庫訪問介面DAO、RDO相比具有更大的靈活性,使用也更方便,開發效率大為提高。
ADOX是核心ADO物件的擴充套件庫。它提供的附加物件可用於建立、修改和刪除模式物件,如表和過程。要使用ADOX,則應建立對ADOX型別庫的引用。ADOX庫檔名為Msadox.dll。
通俗地講,ADO是訪問資料庫的一種介面,可以使用它方便地進行資料庫程式設計。而ADOX是微軟對ADO功能的擴充套件,比如:可以ADOX
ADOX建立ACCESS資料庫
用ADOX建立access資料庫方法很簡單,只需要建立一個Catalog物件,然後呼叫它的Create方法就可以了。
例程ADOXCreateDatabase演示如何使用ADOX建立一個ACCESS資料庫。
開啟VC++ 6.0,新建一個基於對話方塊的工程ADOXCreateDatabase。在對話方塊IDD_ADOXCREATEDATABASE_DIALOG中新增一個編輯框IDC_DBNAME和一個按鈕IDC_BTN_CREATE,編輯框用以輸入資料庫名稱。
使用ClassWizard給編輯框建立一個
雙擊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());
}
}
}
這段程式碼先用ADOX的Catalog物件檢查表是否已經存在,如果該表已經存在,直接返回;如果還沒有該表,使用ADO的Connection物件的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")
關於這兩條語句,需要進行特別說明:
由於該例程同時使用ADOX和ADO,需要同時引入msado15.dll和msadox.dll兩個庫。這兩個庫的名字空間是不同的,msado15.dll的名字空間是ADODB,msadox.dll的名字空間是ADOX。在使用ADO所屬的名字空間的變數,函式時,在前面加上ADODB::,在使用ADOX所屬的名字空間的變數,函式時,在前面加上ADOX::。
另外,一般ADOX和ADO分開操作。您也可以在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::需要完全省略掉。
由於ADOX和ADO有定義衝突,也就是說,msado15.dll和msadox.dll有相同的定義部分,所以在一個程式中,不允許同時使用no_namespace。
使用_ConnectionPtr介面開發ACCESS資料庫
ADO中最重要的物件有三個:Connection、Recordset和Command,分別表示連線物件、記錄集物件和命令物件。三個物件對應的智慧指標分別是:_ConnectionPtr、_RecordsetPtr、_CommandPtr。ADO使用_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, FirstName,LastName,HireDate FROM Employees
結果會顯示該表中所有行的指定欄位的資料。
顯式指定所需欄位還允許我們控制欄位返回的順序,如果我們希望LastName顯示在FirstName之前,我們可以編寫以下語句:
SELECT EmployeeID, LastName,FirstName,HireDate FROM Employees
WHERE子句
接下來我們要做的是開始限制或篩選從資料庫提取的資料。通過向SELECT語句新增WHERE子句,我們可以新增一個(或多個)條件,所選資料必須滿足這些條件,這將限制答覆查詢的行數也就是被提取的行數。
我們可以在上一個查詢的基礎上,將其限制為City為London的員工
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 |
|