结合ADO、ADOX和MFC的文档/视图/框架架构创建和打开Access数据库
本文描述了如何在MFC的文档/视图/框架架构中使用ADO和ADOX来创建和打开数据库。 预备阅读 MFC技术文章 TN025: Document, View, and Frame Creation 微软知识库文章 Q183606 ActiveX Data Objects (ADO) Frequently Asked Questions Q169496 INFO: Using Acti
本文描述了如何在MFC的文档/视图/框架架构中使用ADO和ADOX来创建和打开数据库。
预备阅读
MFC技术文章
- TN025: Document, View, and Frame Creation
微软知识库文章
- Q183606 ActiveX Data Objects (ADO) Frequently Asked Questions
- Q169496 INFO: Using ActiveX Data Objects (ADO) via #import in VC++
- Q317881 HOW TO: Create an Access Database Using ADOX and Visual C# .NET
- Q252908 HOWTO: Create a Table with Primary Key Through ADOX
- Q201826 PRB: Error 3265 When You Access Properties Collection
Office VBA参考
- Creating and Modifying Access Tables
步骤
- 在计算机上安装MDAC2.5以上版本
- 打开VC。首先,我们使用MFC应用程序向导创建一个标准的MDI程序,这里我为这个工程起名为Passport,然后在stdafx.h中导入ADOX
#include
#import "c:/Program Files/Common Files/system/ado/Msado15.dll" rename("EOF","adoEOF") rename("DataTypeEnum","adoDataTypeEnum")
#import "c:/Program Files/Common Files/System/ADO/Msadox.dll" rename("EOF", "adoXEOF") rename("DataTypeEnum","adoXDataTypeEnum")
#import "c:/PROGRAM FILES/COMMON FILES/System/ado/MSJRO.DLL"
根据你的计算机上ADO的安装路径,这里的路径可能有所不同。 - 在文档类中声明数据库连接 ADODB::_ConnectionPtr m_pConn;和记录集 ADODB::_RecordsetPtr m_pSet;,并且重载文档类的DeleteContents() 、OnNewDocument()和OnOpenDocument()函数,用于断开数据库连接,创建数据库和表,以及打开现有的数据库。
(作者的抱怨:CSDN文章中心该改改了,代码排版这么麻烦)
void CPassportDoc::DeleteContents()
{
try
{
if(m_pSet){
ESRecordsetClose(m_pSet);
}
if(m_pConn)
if(m_pConn->State&ADODB::adStateOpen)
m_pConn->Close();
m_pConn=NULL;
}
catch(_com_error &e){
ESErrPrintProviderError(m_pConn);
ESErrPrintComError(e);
}
CDocument::DeleteContents();
}BOOL CPassportDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
CFileDialog dlgFile(FALSE, _T(".mdb"), NULL, OFN_HIDEREADONLY | OFN_PATHMUSTEXIST, _T("Access 数据库 (*.mdb)|*.mdb|全部文件(*.*)|*.*||"));
if (dlgFile.DoModal() != IDOK)
return FALSE;
CString strDBPath=dlgFile.GetPathName();
if(!CreateDB(strDBPath))return FALSE;
//create
CString strConnect;
strConnect.Format(_T("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s"),strDBPath);
COleVariant Connect(strConnect);
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
try{
m_pConn.CreateInstance(_T("ADODB.Connection"));
m_pSet.CreateInstance(_T("ADODB.Recordset"));
m_pConn->PutCommandTimeout(30);
m_pConn->PutConnectionTimeout(30);
m_pConn->put_CursorLocation(ADODB::adUseClient);
m_pConn->Open(_bstr_t(strConnect),_bstr_t(),_bstr_t(),ADODB::adConnectUnspecified);
::ESRecordsetOpen(_T("Passport"),m_pConn,m_pSet);
SetPathName(strDBPath);
return TRUE;
}
catch(_com_error &e){
ESErrPrintProviderError(m_pConn);
ESErrPrintComError(e);
}
catch(...){
}
m_pConn=NULL;
return FALSE;
}
BOOL CPassportDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
ADODB::_ConnectionPtr tempConnn;
CString strConnect;
CString strDBPath=lpszPathName;
strConnect.Format(_T("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s"),strDBPath);
COleVariant Connect(strConnect);
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
try{
tempConnn.CreateInstance(_T("ADODB.Connection"));
tempConnn->PutCommandTimeout(30);
tempConnn->PutConnectionTimeout(30);
tempConnn->put_CursorLocation(ADODB::adUseClient);
tempConnn->Open(_bstr_t(strConnect),_bstr_t(),_bstr_t(),ADODB::adConnectUnspecified);
SetPathName(strDBPath);
m_pConn=tempConnn;
m_pSet=NULL;
m_pSet.CreateInstance(_T("ADODB.Recordset"));
::ESRecordsetOpen(_T("Passport"),m_pConn,m_pSet);
UpdateAllViews(NULL,UpdateHintRefresh);
return TRUE;
}
catch(_com_error &e){
ESErrPrintProviderError(tempConnn);
ESErrPrintComError(e);
}
catch(...){
}
return FALSE;
}
- 编写一个辅助函数,用于创建数据库、表和索引
BOOL CPassportDoc::CreateDB(LPCTSTR lpszFile)
{
if(::PathFileExists(lpszFile)){
CString strTemp;
strTemp.Format(IDS_TARGET_EXISTS,lpszFile);
AfxMessageBox(lpszFile);
return FALSE;
}
ADODB::_ConnectionPtr tempConnn;
ADOX::_CatalogPtr pCatalog = NULL;
ADOX::_TablePtr pTable = NULL;
ADOX::_IndexPtr pIndexNew = NULL;
ADOX::_IndexPtr pIndex = NULL;
CString strConnect;
CString strDBPath=lpszFile;
strConnect.Format(_T("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s"),strDBPath);
COleVariant Connect(strConnect);
try{
pCatalog.CreateInstance(_T("ADOX.Catalog"));
pCatalog->Create((LPCTSTR)strConnect);//创建数据库
tempConnn.CreateInstance(_T("ADODB.Connection"));
tempConnn->PutCommandTimeout(30);
tempConnn->PutConnectionTimeout(30);
tempConnn->put_CursorLocation(ADODB::adUseClient);
tempConnn->Open(_bstr_t(strConnect),_bstr_t(),_bstr_t(),ADODB::adConnectUnspecified);
pCatalog->PutActiveConnection(_variant_t((IDispatch *) tempConnn));
pTable.CreateInstance(_T("ADOX.Table"));
pTable->ParentCatalog =pCatalog;
pTable->Name="Passport";
ADOX::ColumnsPtr pCols =pTable->Columns;
pCols->Append(_T("RecordID") ,ADOX::adInteger,0);//自动编号字段
pCols->Append(_T("Name") ,ADOX::adWChar,255);//文本字段
pCols->Append(_T("DateOfBirth") ,ADOX::adDate,0);//日期字段
pCols->Append(_T("OtherInfo"),ADOX::adLongVarWChar,0);//备注字段
pCatalog->Tables->Refresh();
long lCount=pCols->Count;
for(long i=0;ipCols->GetItem(i)->ParentCatalog =pCatalog;//重要!设置Catalog,参见Q201826 PRB: Error 3265 When You Access Properties Collection
ADOX::PropertiesPtr pProperties=pCols->GetItem(i)->Properties;
if(pProperties){//这里是用于调试的属性显示代码
long lp=pProperties->Count;
TRACE("Properties for Col %s/r/n",(LPCTSTR)pCols->GetItem(i)->Name);
for(long j=0;jTRACE("/rProperty %s:%s/r/n",g_GetValueString(pProperties->GetItem(j)->Name)
,g_GetValueString(pProperties->GetItem(j)->Value));
}
}
}
pCols->GetItem(_T("RecordID"))->Properties->GetItem(_T("Description"))->Value=_T("记录编号");//注释
pCols->GetItem(_T("RecordID"))->Properties->GetItem(_T("AutoIncrement"))->Value=true;//自动编号
pCols->GetItem(_T("Name"))->Properties->GetItem(_T("Jet OLEDB:Compressed UniCode Strings"))->Value=true;
pCols->GetItem(_T("Name"))->Properties->GetItem(_T("Description"))->Value=_T("姓名");
pCols->GetItem(_T("DateOfBirth"))->Properties->GetItem(_T("Description"))->Value=_T("出生日期");
pCols->GetItem(_T("OtherInfo"))->Properties->GetItem(_T("Jet OLEDB:Compressed UniCode Strings"))->Value=true;
pCols->GetItem(_T("OtherInfo"))->Properties->GetItem(_T("Description"))->Value=_T("其他信息");
pCatalog->Tables->Append(_variant_t ((IDispatch*)pTable));//添加表
pCatalog->Tables->Refresh();//刷新
pIndexNew.CreateInstance(_T("ADOX.Index"));
pIndexNew->Name = "RecordID";//索引名称
pIndexNew->Columns->Append("RecordID",ADOX::adInteger,0);//索引字段
pIndexNew->PutPrimaryKey(-1);//主索引
pIndexNew->PutUnique(-1);//唯一索引
pTable->Indexes->Append(_variant_t ((IDispatch*)pIndexNew));//创建索引
pIndexNew=NULL;
pCatalog->Tables->Refresh();//刷新
return TRUE;
}
catch(_com_error &e){
ESErrPrintProviderError(tempConnn);
ESErrPrintComError(e);
return FALSE;
}
catch(...){
}
return FALSE;
} - 辅助的数据库函数。由于这些函数是Jiangsheng以前为一个项目写的。所以命名有些奇怪。借鉴了MFC类CDaoRecordset的部分代码
#define _countof(array) (sizeof(array)/sizeof(array[0]))
BOOL ESRecordsetOpen(
LPCTSTR lpszSQL
,ADODB::_ConnectionPtr pConnection
,ADODB::_RecordsetPtr& rst
,ADODB::CursorTypeEnum CursorType//=adOpenDynamic
,ADODB::LockTypeEnum LockType//=ado20::adLockOptimistic
,long lOptions//=adCmdUnspecified
)
{
_bstr_t bstrQuery;
const TCHAR _afxParameters2[] = _T("PARAMETERS ");
const TCHAR _afxSelect2[] = _T("SELECT ");
const TCHAR _afxTransform2[] = _T("TRANSFORM ");
const TCHAR _afxTable2[] = _T("TABLE ");
// construct the default query string
if ((_tcsnicmp(lpszSQL, _afxSelect2, _countof(_afxSelect2)-1) != 0) &&
(_tcsnicmp(lpszSQL, _afxParameters2, _countof(_afxParameters2)-1) != 0) &&
(_tcsnicmp(lpszSQL, _afxTransform2, _countof(_afxTransform2)-1) != 0) &&
(_tcsnicmp(lpszSQL, _afxTable2, _countof(_afxTable2)-1) != 0)){
CString strTemp;
strTemp.Format("SELECT * FROM (%s)",lpszSQL);
bstrQuery=(LPCTSTR)strTemp;
}
else
bstrQuery=lpszSQL;
if(rst!=NULL){
rst->CursorLocation=ADODB::adUseClient;
rst->Open(bstrQuery,_variant_t(pConnection.GetInterfacePtr(),true),CursorType,LockType,lOptions);
}
TRACE("Open Recordset:%s/n",lpszSQL);
return ESRecordsetIsOpen(rst);
}
BOOL ESRecordsetIsOpen(const ADODB::_RecordsetPtr& rst)
{
if(rst!=NULL){
return rst->State&ADODB::adStateOpen;
}
return FALSE;
}
void ESRecordsetClose(ADODB::_RecordsetPtr& rst)
{
if(rst!=NULL){
if(rst->State&ADODB::adStateOpen)
rst->Close();
}
}
CString g_GetValueString(const _variant_t& val)
{
CString strVal;
_variant_t varDest(val);
if(!g_varIsValid(val)){
return strVal;
}
if(val.vt==VT_BOOL){
if(val.boolVal==VARIANT_FALSE){
return _T("否");
}
else
return _T("是");
}
else{
}
if(varDest.vt!=VT_BSTR){
HRESULT hr=::VariantChangeType(&varDest,&varDest,VARIANT_NOUSEROVERRIDE|VARIANT_LOCALBOOL,VT_BSTR);
if(FAILED(hr)){
return strVal;
}
}
strVal=(LPCTSTR)_bstr_t(varDest);
return strVal;
} - 错误处理代码
void ESErrPrintComError(_com_error &e)
{
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
CString strTemp;
strTemp.Format(_T("´错误/n/t错误代码: %08lx/n/t含义: %s/n/t来自 : %s/n/t描述 : %s/n"),
e.Error(),e.ErrorMessage(),(LPCSTR) bstrSource,(LPCSTR) bstrDescription);
// Print COM errors.
::AfxMessageBox(strTemp);
#ifdef _DEBUG
AfxDebugBreak();
#endif
}
void ESErrPrintProviderError(ADODB::_ConnectionPtr pConnection)
{
if(pConnection==NULL) return;
try{
// Print Provider Errors from Connection object.
// pErr is a record object in the Connection's Error collection.
ADODB::ErrorPtr pErr = NULL;
ADODB::ErrorsPtr pErrors=pConnection->Errors;
if(pErrors){
if( (pErrors->Count) > 0){
long nCount = pErrors->Count;
// Collection ranges from 0 to nCount -1.
for(long i = 0;i pErr = pErrors->GetItem(i);
CString strTemp;
strTemp.Format(_T("/t 错误代码: %x/t%s"), pErr->Number, pErr->Description);
}
}
}
}
catch(_com_error &e){
ESErrPrintComError(e);
}
}
总结
在文档/视图/框架架构中集成数据库访问总体来说还是难度不大的。微软提供了很多示例的代码,大部分工作只是把示例代码从其他语言改写到VC。主要的工作是对MFC的文档/视图/框架架构的理解,在适当的时候调用这些代码。
尽管我在打开数据库的同时也打开了一个记录集,但是我并未给出显示记录集内容的代码,这超出了本文的范围。我可以给出的提示是使用现成的数据列表控件来显示,微软知识库文章Q229029 SAMPLE: AdoDataGrid.exe Demonstrates How to Use ADO with DataGrid Control Using Visual C++可以作为参考。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

Go框架架構的學習曲線取決於對Go語言和後端開發的熟悉程度以及所選框架的複雜性:對Go語言的基礎知識有較好的理解。具有後端開發經驗會有所幫助。複雜度不同的框架導致學習曲線差異。

評估Java框架商業支援的性價比涉及以下步驟:確定所需的保障等級和服務等級協定(SLA)保證。研究支持團隊的經驗和專業知識。考慮附加服務,如昇級、故障排除和效能最佳化。權衡商業支援成本與風險緩解和提高效率。

PHP框架的學習曲線取決於語言熟練度、框架複雜性、文件品質和社群支援。與Python框架相比,PHP框架的學習曲線較高,而與Ruby框架相比,則較低。與Java框架相比,PHP框架的學習曲線中等,但入門時間較短。

写在前面&笔者的个人理解最近来,随着深度学习技术的发展和突破,大规模的基础模型(FoundationModels)在自然语言处理和计算机视觉领域取得了显著性的成果。基础模型在自动驾驶当中的应用也有很大的发展前景,可以提高对于场景的理解和推理。通过对丰富的语言和视觉数据进行预训练,基础模型可以理解和解释自动驾驶场景中的各类元素并进行推理,为驾驶决策和规划提供语言和动作命令。基础模型可以根据对驾驶场景的理解来实现数据增强,用于提供在常规驾驶和数据收集期间不太可能遇到的长尾分布中那些罕见的可行

輕量級PHP框架透過小體積和低資源消耗提升應用程式效能。其特點包括:體積小,啟動快,記憶體佔用低提升響應速度和吞吐量,降低資源消耗實戰案例:SlimFramework創建RESTAPI,僅500KB,高響應性、高吞吐量

編寫清晰全面的文件對於Golang框架至關重要。最佳實踐包括:遵循既定文件風格,例如Google的Go程式設計風格指南。使用清晰的組織結構,包括標題、子標題和列表,並提供導覽。提供全面且準確的信息,包括入門指南、API參考和概念。使用程式碼範例說明概念和使用方法。保持文件更新,追蹤變更並記錄新功能。提供支援和社群資源,例如GitHub問題和論壇。建立實際案例,如API文件。

如何使用Go框架文檔?確定文件類型:官網、GitHub儲存庫、第三方資源。了解文件結構:入門指南、深入教學、參考手冊。根據需要定位資訊:使用組織結構或搜尋功能。理解術語和概念:仔細閱讀並理解新的術語和概念。實戰案例:使用Beego創建一個簡單的Web伺服器。其他Go框架文件:Gin、Echo、Buffalo、Fiber。

根據應用場景選擇最佳Go框架:考慮應用類型、語言特性、效能需求、生態系統。常見Go框架:Gin(Web應用)、Echo(Web服務)、Fiber(高吞吐量)、gorm(ORM)、fasthttp(速度)。實戰案例:建構RESTAPI(Fiber),與資料庫互動(gorm)。選擇框架:效能關鍵選fasthttp,靈活Web應用選Gin/Echo,資料庫互動選gorm。
