事情是這樣的,我的女朋友想要對日常生活的開銷做個記錄,以便控制花錢的尺度。看她每日用筆頭記錄,然後和我搶電腦用,曰:要用附件中的計算器統計結果,每每如此 ,不勝其煩,就給她做了一個個人家庭記帳系統,一勞永逸解決問題。期間用到了ADO操作Access數據庫,在網上找了若干關於ADO的資料結合實踐總結了一點使用心得如下 ,供有相同需求的朋友參考:

附帶了那個個人記帳系統,運行的界面如下:

VC++下使用ADO編寫數據庫程序

準備:

(1)、引入ADO類


view source


print

?


1. 
   #import "c:\program files\common files\system\ado\msado15.dll" \ 
 
  
 
   2. 
   no_namespace \ 
 
  
 
   3. 
   rename ("EOF", "adoEOF")    


(2)、初始化COM

在MFC中可以用AfxOleInit();非MFC環境中用:


view source


print

?


1. 
   CoInitialize(NULL); 
 
  
 
   2. 
   CoUnInitialize();


(3)#import 包含後就可以用3個智能指針了:_ConnectionPtr、_RecordsetPtr和_CommandPtr

1.連接和關閉數據庫 (1)連接

例子:連接Access數據庫


view source


print

?



01. 
   m_pConnection.CreateInstance(__uuidof(Connection)); 
 
  
 
   02. 
   try                 
 
  
 
   03. 
   {    
 
  
 
   04. 
   // 打開本地Access庫Demo.mdb 
 
  
 
   05. 
   m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;DataSource=Demo.mdb", 
 
  
 
   06. 
   "","",adModeUnknown); 
 
  
 
   07. 
   } 
 
  
 
   08. 
   catch(_com_error e) 
 
  
 
   09. 
   { 
 
  
 
   10. 
   AfxMessageBox("數據庫連接失敗,確認數據庫Demo.mdb是否在當前路徑下!"); 
 
  
 
   11. 
   return FALSE; 
 
  
 
   12. 
   }           



(2)、關閉

//如果數據庫連接有效


view source


print

?

1. 
   if(m_pConnection->State) 
 
  
 
   2. 
   m_pConnection->Close(); 
 
  
 
   3. 
   m_pConnection= NULL;


(3)、設置連接時間 //設置連接時間-----------------------------------


view source


print

?

1. 
   pConnection->put_ConnectionTimeout(long(5));

2.打開一個結果集

(1)打開,首先創建一個_RecordsetPtr實例,然後調用Open()得到一條SQL語句的執行結果


view source


print

?


01. 
   _RecordsetPtr   m_pRecordset; 
 
  
 
   02. 
   m_pRecordset.CreateInstance(__uuidof(Recordset)); 
 
  
 
   03. 
    
 
  
 
   04. 
   // 在ADO操作中建議語句中要常用try...catch()來捕獲錯誤信息, 
 
  
 
   05. 
   // 因為它有時會經常出現一些意想不到的錯誤。jingzhou xu 
 
  
 
   06. 
   try
 
  
 
   07. 
   { 
 
  
 
   08. 
   m_pRecordset->Open("SELECT * FROM DemoTable",// 查詢DemoTable表中所有字段 
 
  
 
   09. 
   m_pConnection.GetInterfacePtr(),  // 獲取庫接庫的IDispatch指針 
 
  
 
   10. 
   adOpenDynamic, 
 
  
 
   11. 
   adLockOptimistic, 
 
  
 
   12. 
   adCmdText); 
 
  
 
   13. 
   } 
 
  
 
   14. 
   catch(_com_error *e) 
 
  
 
   15. 
   { 
 
  
 
   16. 
   AfxMessageBox(e->ErrorMessage()); 
 
  
 
   17. 
   } 
 
  
 
   18.


(2)關閉結果集


view source


print

?



1. 
   m_pRecordset->Close();

3.操作一個結果集

(1)、遍歷(讀取)

a)、用pRecordset->adoEOF來判斷數據庫指針是否已經移到結果集的末尾了;m_pRecordset->BOF判斷是否 在第一條記錄前面:


view source 
   
 
   print 
   ? 
   
 
 
   01. 
   while(!m_pRecordset->adoEOF) 
 
  
 
   02. 
   { 
 
  
 
   03. 
   var = m_pRecordset->GetCollect("Name"); 
 
  
 
   04. 
   if(var.vt != VT_NULL) 
 
  
 
   05. 
   strName = (LPCSTR)_bstr_t(var); 
 
  
 
   06. 
   var = m_pRecordset->GetCollect("Age"); 
 
  
 
   07. 
   if(var.vt != VT_NULL) 
 
  
 
   08. 
   strAge = (LPCSTR)_bstr_t(var); 
 
  
 
   09. 
   m_AccessList.AddString( strName + " --> "+strAge ); 
 
  
 
   10. 
   m_pRecordset->MoveNext(); 
 
  
 
   11. 
   } 
 
  
 
   12.


b)、取得一個字段的值的辦法有兩種辦法

一是

//表示取得第0個字段的值


view source


print

?


1. 
   m_pRecordset->GetCollect("Name");

或者


view source


print

?


1. 
   m_pRecordset->GetCollect(_variant_t(long(0));
 
二是


view source


print

?



1. 
   pRecordset->get_Collect("COLUMN_NAME");
 
或者


view source


print

?


1. 
   pRecordset->get_Collect(long(index));

(2)、添加

     a)、調用m_pRecordset->AddNew();

     b)、調用m_pRecordset->PutCollect();給每個字段賦值

     c)、調用m_pRecordset->Update();確認

(3)、修改

(4)、刪除

     a)、把記錄指針移動到要刪除的記錄上,然後調用Delete(adAffectCurrent)


view source


print 
   ? 
   
 
 
   01. 
   try
 
  
 
   02. 
   { 
 
  
 
   03. 
   // 假設刪除第二條記錄 
 
  
 
   04. 
   m_pRecordset->MoveFirst(); 
 
  
 
   05. 
   m_pRecordset->Move(1);         
 
  
 
   06. 
   // 從0開始 
 
  
 
   07. 
   m_pRecordset->Delete(adAffectCurrent);   
 
  
 
   08. 
   // 參數adAffectCurrent為刪除當前記錄 
 
  
 
   09. 
   m_pRecordset->Update(); 
 
  
 
   10. 
   } 
 
  
 
   11. 
   catch(_com_error *e) 
 
  
 
   12. 
   { 
 
  
 
   13. 
   AfxMessageBox(e->ErrorMessage()); 
 
  
 
   14. 
   }

4.直接執行SQL語句,除了要用到結果集其餘的大部分功能都可以直接用SQL語言實現

(1)、用_CommandPtr和_RecordsetPtr配合


view source


print 
   ? 
   
 
 
   1. 
   _CommandPtr     m_pCommand; 
 
  
 
   2. 
   m_pCommand.CreateInstance(__uuidof(Command)); 
 
  
 
   3. 
   // 將庫連接賦於它 
 
  
 
   4. 
   m_pCommand->ActiveConnection = m_pConnection;   
 
  
 
   5. 
   // SQL語句 
 
  
 
   6. 
   m_pCommand->CommandText = "SELECT * FROM DemoTable";   
 
  
 
   7. 
   // 執行SQL語句,返回記錄集 
 
  
 
   8. 
   m_pRecordset = m_pCommand->Execute(NULL, NULL,adCmdText);    

(2)、直接用_ConnectionPtr執行SQL語句


view source


print

?



01. 
   _RecordsetPtr Connection15::Execute ( _bstr_t CommandText,  
 
  
 
   02. 
   VARIANT * RecordsAffected,  
 
  
 
   03. 
   long Options )  
 
  
 
   04. 
    
 
  
 
   05. 
   其中CommandText是命令字串,通常是SQL命令。  
 
  
 
   06. 
   參數RecordsAffected是操作完成後所影響的行數,  
 
  
 
   07. 
   參數Options表示CommandText中內容的類型,Options可以取如下值之一:  
 
  
 
   08. 
   adCmdText:表明CommandText是文本命令  
 
  
 
   09. 
   adCmdTable:表明CommandText是一個表名  
 
  
 
   10. 
   adCmdProc:表明CommandText是一個存儲過程  
 
  
 
   11. 
   adCmdUnknown:未知 
 
  
 
   12. 
    
 
  
 
   13. 
   例子: 
 
  
 
   14. 
   _variant_t RecordsAffected; 
 
  
 
   15. 
   m_pConnection->Execute("UPDATE users SET old = old+1",&RecordsAffected,adCmdText);   


5.調用存儲過程

(1)、利用_CommandPtr


view source


print

?



1. 
   _CommandPtr m_pCommand; 
 
  
 
   2. 
   m_pCommand.CreateInstance(__uuidof(Command)); 
 
  
 
   3. 
   m_pCommand->ActiveConnection = m_pConnection;  // 將庫連接賦於它 
 
  
 
   4. 
   m_pCommand->CommandText = "Demo";   
 
  
 
   5. 
   m_pCommand->Execute(NULL,NULL, adCmdStoredProc);     


(2)、直接用_ConnectionPtr直接調用(見4.(2))

6.遍歷數據庫中的所有表名


view source

print 
   ? 
   
 
 
   01. 
   _ConnectionPtr m_pConnect;  
 
  
 
   02. 
   _RecordsetPtr pSet;  
 
  
 
   03. 
   HRESULT hr;  
 
  
 
   04. 
   try 
 
  
 
   05. 
   {   
 
  
 
   06. 
   hr = m_pConnect.CreateInstance("ADODB.Connection");     
 
  
 
   07. 
   if(SUCCEEDED(hr))   
 
  
 
   08. 
   {    
 
  
 
   09. 
   CString dd;    
 
  
 
   10. 
   dd.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s",file);    
 
  
 
   11. 
   hr = m_pConnect->Open((_bstr_t)dd,"","",adModeUnknown);    
 
  
 
   12. 
   pSet = m_pConnect->OpenSchema(adSchemaTables);       
 
  
 
   13. 
   while(!(pSet->adoEOF))    
 
  
 
   14. 
   {          
 
  
 
   15. 
   //獲取表格     
 
  
 
   16. 
   _bstr_t table_name = pSet->Fields->GetItem("TABLE_NAME")->Value; 
 
  
 
   17. 
    
 
  
 
   18. 
   //獲取表格類型         
 
  
 
   19. 
   _bstr_t table_type = pSet->Fields->GetItem("TABLE_TYPE")->Value; 
 
  
 
   20. 
    
 
  
 
   21. 
   //過濾一下,只輸出表格名稱,其他的省略 
 
  
 
   22. 
   if ( strcmp(((LPCSTR)table_type),"TABLE")==0){ 
 
  
 
   23. 
   CString tt; 
 
  
 
   24. 
   tt.Format("%s",(LPCSTR)table_name);      
 
  
 
   25. 
   AfxMessageBox(tt);         
 
  
 
   26. 
   }        
 
  
 
   27. 
   pSet->MoveNext();     
 
  
 
   28. 
   }    
 
  
 
   29. 
   pSet->Close();   
 
  
 
   30. 
   }   
 
  
 
   31. 
   m_pConnect->Close();   
 
  
 
   32. 
   }catch(_com_error e)///捕捉異常  
 
  
 
   33. 
   {   
 
  
 
   34. 
   CString errormessage;   
 
  
 
   35. 
   errormessage.Format("連接數據庫失敗!rn錯誤信息:%s",e.ErrorMessage()); 
 
  
 
   36. 
    
 
  
 
   37. 
   AfxMessageBox(errormessage); 
 
  
 
   38. 
   return -1; 
 
  
 
   39. 
   }       


7.遍歷一個表中的所有字段


view source


print

?

01. 
   Field *   field = NULL;      
 
  
 
   02. 
   HRESULT   hr; 
 
  
 
   03. 
   Fields *  fields = NULL; 
 
  
 
   04. 
   hr = m_pRecordset->get_Fields (&fields); //得到記錄集的字段集和     
 
  
 
   05. 
    
 
  
 
   06. 
   if(SUCCEEDED(hr))  
 
  
 
   07. 
   fields->get_Count(&ColCount);     
 
  
 
   08. 
    
 
  
 
   09. 
   //得到記錄集的字段集合中的字段的總個數     
 
  
 
   10. 
   for(i=0;iItem[i]->get_Name(&bstrColName);    //得到記錄集//中的字段名 
 
  
 
   11. 
   strColName=bstrColName;  
 
  
 
   12. 
   nameField = strColName; 
 
  
 
   13. 
   m_FieldsList.AddString(nameField); 
 
  
 
   14. 
   } 
 
  
 
   15. 
   if(SUCCEEDED(hr)) 
 
  
 
   16. 
   fields->Release();//釋放指針


附:

1、_variant_t

(1)、一般傳給這3個指針的值都不是MFC直接支持的數據類型,而要用_variant_t轉換一下_variant_t(XX)可以把大多數類型的變量轉換成適合的類型傳入:

(2)、_variant_t var;


view source


print

?


1. 
   _variant_t -> long: (long)var; 
 
  
 
   2. 
   _variant_t -> CString: CString strValue = (LPCSTR)_bstr_t(var); 
 
  
 
   3. 
   CString -> _variant_t: _variant_t(strSql);


2、BSTR寬字符串與CString相互轉換


view source


print

?


1. 
   BSTR bstr; 
 
  
 
   2. 
   CString strSql; 
 
  
 
   3. 
   CString -> BSTR: bstr = strSql.AllocSysString(); 
 
  
 
   4. 
   BSTR -> CString: strSql = (LPCSTR)bstr;


3、_bstr_t與CString相互轉換


view source


print 
   ? 
   
 
 
   1. 
   _bstr_t bstr; 
 
  
 
   2. 
   CString strSql; 
 
  
 
   3. 
   CString -> _bstr_t: bstr = (_bstr_t)strSql; 
 
  
 
   4. 
   _bstr_t -> CString: strSql = (LPCSTR)bstr;

4、關於時間

Access:表示時間的字符串#2004-4-5#

Sql:表示時間的字符串''2004-4-5''

DateField(時間字段) select * from my_table where DateField > #2004-4-10#