ADO (ActiveX Data Objects) 建於 OLE DB 之上,提供簡潔、高階的資料存取介面,支援 Access、SQL Server、Oracle 等多種資料源。本文以 Access 2000 (`test.mdb`) 為例,示範 VC++ 中 `#import` 引入 ADO 型別庫、連接資料庫、執行 SQL、Recordset 操作與完整 CRUD 範例。
#import "C:\\Program Files\\Common Files\\System\\ADO\\msado15.dll" \
no_namespace rename("EOF", "adoEOF")
※ 路徑視安裝位置調整。編譯會產生 `msado15.tlh/tli`。忽略 `C4146` 警告。
BOOL CMyApp::InitInstance() {
AfxOleInit(); // 或 CoInitialize(NULL)
// ...
}
_ConnectionPtr m_pConn;
HRESULT hr;
try {
hr = m_pConn.CreateInstance(__uuidof(Connection));
if (SUCCEEDED(hr)) {
hr = m_pConn->Open(
_bstr_t("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=test.mdb"),
_bstr_t(""), _bstr_t(""), adModeUnknown);
// Access 97 用 Provider=Microsoft.Jet.OLEDB.3.51
}
}
catch (_com_error& e) {
CString msg; msg.Format(_T("連接失敗: %s"), e.ErrorMessage());
AfxMessageBox(msg);
}
_variant_t rowsAffected;
// 建表
m_pConn->Execute(_bstr_t("CREATE TABLE Users(ID INT, Name TEXT, Age INT, Birthday DATETIME)"), &rowsAffected, adCmdText);
// 新增
m_pConn->Execute(_bstr_t("INSERT INTO Users VALUES(1, 'John', 25, '1990-1-1')"), &rowsAffected, adCmdText);
// 更新
m_pConn->Execute(_bstr_t("UPDATE Users SET Age = Age + 1"), &rowsAffected, adCmdText);
// 查詢計數
_RecordsetPtr rs = m_pConn->Execute(_bstr_t("SELECT COUNT(*) FROM Users"), &rowsAffected, adCmdText);
_variant_t cnt = rs->GetCollect(_variant_t((long)0));
rs->Close();
_CommandPtr cmd;
cmd.CreateInstance(__uuidof(Command));
cmd->ActiveConnection = m_pConn;
cmd->CommandText = _bstr_t("SELECT * FROM Users");
_RecordsetPtr rs = cmd->Execute(NULL, NULL, adCmdText);
_RecordsetPtr rs;
rs.CreateInstance(__uuidof(Recordset));
rs->Open(_bstr_t("SELECT * FROM Users"),
_variant_t((IDispatch*)m_pConn, true),
adOpenStatic, adLockOptimistic, adCmdText);
| 常數 | 值 | 特性 |
|---|---|---|
| adOpenForwardOnly | 0 | 唯前向、唯讀、高效能 |
| adOpenKeyset | 1 | 可見他人更新、不可見新增/刪除 |
| adOpenDynamic | 2 | 即時反映所有變更、支援書籤 |
| adOpenStatic | 3 | 靜態快照、支援書籤/移動、不見他人變更 |
| 常數 | 值 | 特性 |
|---|---|---|
| adLockReadOnly | 1 | 唯讀 |
| adLockPessimistic | 2 | 編輯即鎖定 (悲觀) |
| adLockOptimistic | 3 | Update 時才鎖定 (樂觀,推薦) |
| adLockBatchOptimistic | 4 | 批次更新模式 |
_variant_t vID, vName, vAge, vBD;
_RecordsetPtr rs;
rs.CreateInstance(__uuidof(Recordset));
rs->Open(_bstr_t("SELECT * FROM Users"),
_variant_t((IDispatch*)m_pConn, true),
adOpenStatic, adLockOptimistic, adCmdText);
// 遍歷
while (!rs->adoEOF) { // 注意:rename("EOF","adoEOF")
vID = rs->GetCollect(_variant_t((long)0)); // 索引 0
vName = rs->GetCollect(_bstr_t("Name")); // 或欄位名
vAge = rs->GetCollect(_bstr_t("Age"));
vBD = rs->GetCollect(_bstr_t("Birthday"));
TRACE(_T("ID:%d Name:%s Age:%d BD:%s\n"),
vID.lVal, (LPCTSTR)(_bstr_t)vName, vAge.lVal, (LPCTSTR)(_bstr_t)vBD);
rs->MoveNext();
}
// 刪除第一筆
rs->MoveFirst();
rs->Delete(adAffectCurrent);
// 新增三筆
for (int i=0; i<3; i++) {
rs->AddNew();
rs->PutCollect(_bstr_t("ID"), _variant_t(i+10));
rs->PutCollect(_bstr_t("Name"), _bstr_t("Yeltsin"));
rs->PutCollect(_bstr_t("Age"), _variant_t(71));
rs->PutCollect(_bstr_t("Birthday"), _bstr_t("1930-3-15"));
}
// 修改第二筆年齡
rs->Move(1, _variant_t((long)adBookmarkFirst)); // 從第一筆移動 1 格
rs->PutCollect(_bstr_t("Age"), _variant_t(45));
rs->Update(); // 寫回資料庫
rs->Close();
本文附帶完整專案 `ADOTest1`,包含:
核心類別成員:
_RecordsetPtr m_pRecordset;
_variant_t vUserID, vUsername, vOld, vBirthday;
int m_nCurrentSel;
BOOL m_bAutoSave, m_bSuccess;
if (m_pRecordset) m_pRecordset->Close();
if (m_pConn && m_pConn->State) m_pConn->Close();
// 智慧指標離開範圍自動 Release()