结合ADO、ADOX和MFC的文档/视图/框架架构创建和打开Access数据库

本文描述了如何在MFC的文档/视图/框架架构中使用ADO和ADOX来创建和打开数据库。

预备阅读

在阅读本文之前,建议先对COM,数据库和MFC的文档/视图/框架有一个基本的了解。推荐阅读下列文章

MFC技术文章

微软知识库文章

Office VBA参考

步骤

  1. 在计算机上安装MDAC2.5以上版本
  2. 打开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的安装路径,这里的路径可能有所不同。
  3. 在文档类中声明数据库连接 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;
    }
  4. 编写一个辅助函数,用于创建数据库、表和索引
    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;i
       pCols->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;j
         TRACE("/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;
    }
  5. 辅助的数据库函数。由于这些函数是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;
    }
  6. 错误处理代码
    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 < nCount;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++可以作为参考。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
vc++利用ADOX创建数据库 // ADOXCreateDatabaseDlg.cpp : implementation file // #include "stdafx.h" #include "ADOXCreateDatabase.h" #include "ADOXCreateDatabaseDlg.h" #include "Shlwapi.h" #pragma comment(lib,"shlwapi.lib") // Download by http://www.codefans.net #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) // No message handlers //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CADOXCreateDatabaseDlg dialog CADOXCreateDatabaseDlg::CADOXCreateDatabaseDlg(CWnd* pParent /*=NULL*/) : CDialog(CADOXCreateDatabaseDlg::IDD, pParent) { //{{AFX_DATA_INIT(CADOXCreateDatabaseDlg) m_dbName = _T(""); //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CADOXCreateDatabaseDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CADOXCreateDatabaseDlg) DDX_Text(pDX, IDC_DBNAME, m_dbName); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CADOXCreateDatabaseDlg, CDialog) //{{AFX_MSG_MAP(CADOXCreateDatabaseDlg) ON_WM_SYSCOMM

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值