青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-80  評論-22  文章-0  trackbacks-0
大多數應用程序都使用數據庫,各種管理軟件、ERP、CRM系統均需要數據庫來保存和維護應用程序的數據,在VC中提供了多種數據庫訪問技術,不過目前最流行的是ODBC(開放式數據庫接口)和ADO(活動對象模型)。  
   
  一.數據庫技術初步  
        1.ODBC基本概念  
        ODBC(Open   Database   Connectivity,開放數據庫互連)是微軟公司開放服務結構(WOSA,Windows   Open   Services   Architecture)中有關數據庫的一個組成部分,它建立了一組規范,并提供了一組對數據庫訪問的標準API(應用程序編程接口)。這些API利用SQL來完成其大部分任務。ODBC本身也提供了對SQL語言的支持,用戶可以直接將SQL語句送給ODBC。  
   
    一個基于ODBC的應用程序對數據庫的操作不依賴任何DBMS,不直接與DBMS打交道,所有的數據庫操作由對應的DBMS的ODBC驅動程序完成。也就是說,不論是FoxPro、Access還是Oracle數據庫,均可用ODBC   API進行訪問。由此可見,ODBC的最大優點是能以統一的方式處理所有的數據庫。  
   
    一個完整的ODBC由下列幾個部件組成:  
   
    應用程序(Application)。  
   
    ODBC管理器(Administrator)。該程序位于Windows   95控制面板(Control   Panel)的32位ODBC內,其主要任務是管理安裝的ODBC驅動程序和管理數據源。  
   
    驅動程序管理器(Driver   Manager)。驅動程序管理器包含在ODBC32.DLL中,對用戶是透明的。其任務是管理ODBC驅動程序,是ODBC中最重要的部件。  
   
    ODBC   API。  
   
    ODBC   驅動程序。是一些DLL,提供了ODBC和數據庫之間的接口。  
   
    數據源。數據源包含了數據庫位置和數據庫類型等信息,實際上是一種數據連接的抽象。  
   
    應用程序要訪問一個數據庫,首先必須用ODBC管理器注冊一個數據源,管理器根據數據源提供的數據庫位置、數據庫類型及ODBC驅動程序等信息,建立起ODBC與具體數據庫的聯系。這樣,只要應用程序將數據源名提供給ODBC,ODBC就能建立起與相應數據庫的連接。  
   
    在ODBC中,ODBC   API不能直接訪問數據庫,必須通過驅動程序管理器與數據庫交換信息。驅動程序管理器負責將應用程序對ODBC   API的調用傳遞給正確的驅動程序,而驅動程序在執行完相應的操作后,將結果通過驅動程序管理器返回給應用程序。  
   
    在訪問ODBC數據源時需要ODBC驅動程序的支持。用Visual   C++   5.0安裝程序可以安裝SQL   Server、   Access、   Paradox、   dBase、   FoxPro、   Excel、   Oracle   和Microsoft   Text等驅動程序.在缺省情況下,VC5.0只會安裝SQL   Server、   Access、   FoxPro和dBase的驅動程序.如果用戶需要安裝別的驅動程序,則需要重新運行VC   5.0的安裝程序并選擇所需的驅動程序。    
   
        2.ADO對象訪問模型  
        1)ADO是微軟整個COM戰略體系中的一個組成部分  
   
      活動數據對象(ADO)是一組由微軟提供的COM組件。   ADO建立在微軟所提倡的COM體系結構之上,它的所有接口都是自動化接口,因此在C++、VisualBasic、Delphi等支持COM的開發語言中通過接口都可以訪問到ADO。ADO通過使用OLE   DB這一新技術實現了以相同方式可以訪問關系數據庫、文本文件、非關系數據庫、索引服務器和活躍目錄服務等的數據,擴大了應用程序中可使用的數據源范圍,從而成為微軟整個COM戰略體系中訪問數據源組件的首選,是ODBC的替代產品。
2)ADO對象模型組成  
   
   與微軟的其它數據訪問模型DAO和RDO相比,ADO對象模型非常精煉,僅由三個主要對象Connection、Command、Recordset和幾個輔助對象組成。Connection對象提供OLE   DB數據源和對話對象之間的關聯,它通過用戶名稱和口令來處理用戶身份的鑒別,并提供事務處理的支持;它還提供執行方法,從而簡化數據源的連接和數據檢索的進程。Command對象封裝了數據源可以解釋的命令,該命令可以是SQL命令、存儲過程或底層數據源可以理解的任何內容。Record   set用于表示從數據源中返回的表格數據,它封裝了記錄集合的導航、記錄更新、記錄刪除和新記錄的添加等方法,還提供了批量更新記錄的能力。其它輔助對象則分別提供封裝ADO錯誤、封裝命令參數和封裝記錄集合的列。    
   
   3)ADO的特點分析  
   
    (a)由于封裝了許多底層工作,使用ADO與使用ODBC幾乎是一樣方便。  
    (b)   ADO不僅具有ODBC的主要功能,而且ADO適用的數據源的范圍要大的多。  
    (c)在定義ADO記錄集變量和數據庫表字段綁定類時,要求記錄集的字段變量、狀態變量與數據庫表字段的個數、順序必須相同。這一點比在FMC中使用ODBC要復雜一些。但在數據庫字段與ADO記錄集字段變量綁定的宏中,ADO   提供的數據類型要遠多于FMC中的RFX(如日期時間類型,在ODBC中只能轉換為Cstring類型)。  
    (d)ADO允許同一Connection實例下有多個Record   set實例。  
    (e)ADO允許進行批更新(使用的Update   Batch方法),這樣將大大減輕網絡負擔,提高數據庫處理效率。  
         
      4)   ADO在Visual   C++中的使用  
   
    利用微軟在Micrsoft   Studio   6中提供的ADO2,可以在Visual   C++中使用ADO接口操縱SQL   SERVER數據庫。在編譯型高級語言中使用ADO,比起在一些腳本語言(如Visual   Basic   Scropt和JavaScript)中使用ADO要困難一些。  
   
    以下給出一個Visual   C++下使用ADO的Connection對象及其Record   set對象的基本步驟:  
    (a)   使用import指令引入ADO2組件  
    例:#import   "C:\ADO\msado15.dll"   no_namespace   rename("EOF",   "EndOfFile")    
    (b)   定義CADORecordBinding   的派生類,用于程序與數據庫表字段的交互,該類的定義可參見icrsint.h。  
    例:  
  class   CIntlive   :   public   CADORecordBinding    
  {    
  public:  
  DBTIMESTAMP   m_datetime;   //定義ADO記錄集字段變量(與數據庫表字段相對應)  
  long   m_key;  
  long   m_value;  
  long   m_quality;  
  WORD   m_stsdatetime;   //定義ADO記錄集狀態變量  
  WORD   m_stskey;  
  WORD   m_stsvalue;  
  WORD   m_stsquality;  
  BEGIN_ADO_BINDING(CIntlive)   //將數據庫字段與ADO記錄集字段變量綁定  
  ADO_VARIABLE_LENGTH_ENTRY2(1,adDBTimeStamp,m_datetime,sizeof(m_datetime),m_stsdatetime,true)  
  ADO_NUMERIC_ENTRY(2,adInteger,m_key,10,0,m_stskey,true)  
  ADO_NUMERIC_ENTRY(3,adInteger,m_value,10,0,m_stsvalue,true)  
  ADO_NUMERIC_ENTRY(4,adInteger,m_quality,10,0,m_stsquality,true)  
  END_ADO_BINDING()  
  };  
    (c)   調用CoInitialize初始化COM   ::CoInitialize(NULL);    
    (d)   聲明ADO的Connection對象指針和Recordset對象指針并初始化。(類型名在   msado15.dll中已定義)  
    例:  
  _ConnectionPtr   pConnection1   =   NULL;  
  _RecordsetPtr   rstADO1   =   NULL;    
    (e)   定義CADORecordBinding派生類的實例及其Bind接口指針。  
    例:  
  CIntlive   m_intdata;    
  IADORecordBinding   *rstADOBind1   =   NULL;    
    (f)   產生Connection對象實例和Record   set對象實例。  
    例:  
  pConnection1.CreateInstance(_uuidof(Connection));    
  rstADO1.CreateInstance(__uuidof(Recordset))   ;    
    (g)   連接到數據庫并打開Record   set對象,其中open函數的參數的使用方法可參見微軟MSDN中ADO   相應對象參數的Basic描述。  
    例:  
  PConnection1->Open("driver={SQL   server};server=servera;uid=sa;pwd=;database=pubs","","",NULL);  
  rstADO1->Open("data",   _variant_t((IDispatch   *)pConnection1,true),    
  adOpenKeyset,adLockBatchOptimistic,   adCmdTable);    
    (h)   將CADORecordBinding派生類的實例聯編到Record   set對象的Bind接口。  
    例:  
  RstADOBind1->BindToRecordset(&m_intdata);    
    (i)   對Record   set對象實例進行操作。操作方法可參見微軟MSDN中ADO   Record   set對象相應方法的Basic描述。  
       例:  
  rstADO1->Move   Next();   //移動游標到下一條記錄  
  rstADO1->Update(_variant_t("quality"),_variant_t("3")));   //修改記錄的quality字段的值為3  
  rstADO1->Update   Batch(adAffectAll));   //將在Record   set對象上的所有更新一次送入數據庫  
    (j)   關閉Record   set對象并釋放Bind接口。  
    例:  
  RstADO1->Close();    
  RstADOBind2->Release();    
    (k)   關閉連接   pConnection1->Close();    
    (l)   調用CoUnitialize釋放COM資源   ::CoUninitialize();    
   5)   結論  
    作為ODBC的替代產品,ADO確實有其過人之處。由于ADO數據源幾乎覆蓋了目前常見的數據源類型,對于ODBC所不支持的數據源,ADO無疑是唯一的選擇。而ADO的批更新功能,更是網絡環境下大數據量更新應用的重要因素。由于ADO缺乏大量的第三方廠商的支持,使得ADO目前遠不如ODBC普及,但其面向對象的特性將使ADO具有比較廣闊的發展前景。

3.ADO與ODBC的區別  
        有很多種使用數據庫的方法,對大多數數據庫來說,選擇C++這種產品也許并不適宜。我們知道,像dBASE   IV,FoxPro,Oracle和Access這樣的產品是完全以數據庫管理為中心的。事實上,這些產品非常善于創建數據庫管理器,以至于它們確實并不善于做太多其它的工作。即使要用更通用化而非更專用化的數據庫產品來執行一些類型的工作,在使程序設計更容易這一方面,像VisualBasic和Delphi這樣的RAD環境也要比Visual   C++強很多。  
   
    你是不是對我的說法感到很奇怪?下面我就要談一談,在談到使用數據庫管理系統(DBMS)這個話題時,用Visual   C++實際上可以做些什么。雖然上述其它語言使得編寫成熟的包括用戶界面和高速搜索能力的DBMS就像孩子做游戲一樣容易,但是,它們缺少Visual   C++可以提供的某些重要東西。你不能為使用Access的數據庫輕松地編寫出實用程序。正像實用程序的定義所說的,實用程序應該很小并且具備可移植性——Access應用程序卻不是這樣。即使用Access這樣的產品創建的程序可以很小并且可以移植,你仍有其它方面的需求:底層的功能。  
   
    注:編寫數據庫實用程序及驅動程序時,可以選擇Visual   C++語言。  
   
    想像一下,使用像Visual   Basic這樣的語言來與實時數據采集設備打交道的情況。在進行底層訪問時,RAD的保護環境常常使程序員不能進行有效的處理。當然,數據采集設備幾乎不依賴于簡明的連接。你打算如何把Visual   Basic和外部的數據源連接起來呢?數據源甚至可能不了解Windows,DOS或類似的成熟的操作系統。  
   
    只要使用得當,很容易看到Visual   C++是一種不可或缺的數據庫管理工具。針對大規模的應用程序,即使你仍想依賴于Visual   Basic這樣的RAD語言,也請考慮一下Visual   C++,它創建的程序規模小、提供底層訪問并能提供實時訪問。事實上,你可能還沒有想到,Visual   C++數據庫應用程序的市場是很有潛力的。隨著人們在旅途中越來越多地使用膝上型和掌上型電腦,這兩類電腦上的數據庫應用程序也變得越來越普通。你也許能夠適應今天的膝上型電腦上的Access應用程序,但談到硬盤大小或內存需求時,公司里較老的膝上型電腦可能就達不到要求。運行Windows   CE的掌上型電腦在運行這個Access應用程序時,肯定會發生故障。在這一數據庫市場的新領域,Visual   C++提供了無價無限的工具。  
   
    Web鏈接   談到使用Visual   C++和數據庫,其實你并不孤單。從一開始就有數據庫專用新聞組提供有關數據庫創建技巧的幫助,比如microsoft.public.access。不過,這些新聞組提供的是通用信息,對實際編寫應用程序并非全都那么有用。專門針對Visual   C++問題的新聞組是microsoft.public.vc.database和microsoft.public.vc.mfcdatabase。如果你決定用ODBC訪問數據庫,可能還要查看一下microsoft.public.odbc.sdk新聞組,它討論的不僅僅是SDK。對最新技術感興趣的程序員可以查閱microsoft.public.ado新聞組,或者microsoft.public.oledb(對象鏈接和嵌入數據庫)新聞組,前者討論   ADO,后者討論ADO的基礎技術。在microsoft.public.ado.rds有一個ADO子組,它討論遠程數據訪問。  
   
    既然所有的疑惑都消除了,大多數人的信心也就增強了,下面我們就介紹兩種使C++訪問數據庫中的數據的主要方法:ODBC(開放數據庫互連)和ADO(ActiveX數據對象)。在本章中,將介紹這兩種類型的訪問方法,但我想你會發現,ADO方法是針對新的程序設計情形而采用的。它克服了早期技術的諸多限制,依賴于Microsoft新的底層訪問方法OLE-DB(對象鏈接和嵌入數據庫)。在本書的后面我們會看到,用ADO和Visual   C++提供的各種向導來匯集數據庫工程,其速度有多快。  
   
    注   ODBC通常用來訪問不具備OLE-DB特性的非Microsoft數據庫中的數據;16位的ODBC驅動程序工作起來可能非常緩慢。  
   
    ODBC素以最慢的數據訪問方法而著稱,但是很可惜,當ADO或DAO都不支持某個數據庫管理器而ODBC支持這個數據庫管理器時,在這種特定的情形下,你仍然需要使用ODBC。在大多數情況下,這意味著要從數據庫廠商那里獲得所需的驅動程序,雖然Visual   C++確實附帶了一些產品的驅動程序(如果你正在使用數據庫管理器的某些神秘功能,那么就需要建立自己的接口棗這并不是一件十分困難的事)。本質上講,你總是要使用ODBC來訪問Microsoft產品之外的其它DBMS產品所創建的數據庫,這些數據庫并不具備OLE-DB功能。ODBC還要求做一些額外的工作棗為ADO調整Visual   C++中的大部分向導。  
   
    高級技巧    
   
    除了使用ADO和ODBC外,你還可以使用像DAO(數據訪問對象)這樣的早期技術,該技術包含在像Access這樣的Microsoft產品中。DAO依賴于用Microsoft   Access自動獲得的Microsoft   Jet數據庫引擎。DAO還是較早版的Visual   Basic所使用的引擎(最新版的Visual   Basic和Visual   C++依賴于相同的ADO/OLE-DB組合),所以如果需要支持較早的Visual   Basic應用程序,那么DAO仍是一個不錯的選擇。  
   
    盡管Microsoft文件聲明,可以用DAO訪問非Microsoft產品建立的數據庫,但你仍會發現,在這種情況下,使用ADO和ODBC要好得多。這樣的話,不但兼容性問題會少一些,速度也將有所提高,因為數據請求經過的接口層減少了。有一條經驗要記住,DAO是設計用來處理MDB文件的。  
   
    ADO的一個問題是,它不支持遠程通信。這是Microsoft提出RDO(遠程數據對象)的原因之一。這種特別技術在Visual   Basic應用程序中的使用,要比在Visual   C++中的使用多得多,所以我猜想,你們中有很多人都在使用它。但是,記住RDO仍是一種生命力很強的技術,這一點很重要。ADO確實具有替代RDO的遠程數據服務(RDS)特征。換言之,ADO在一個軟件包中提供了DAO和RDO兩種功能性。

4.MFC中相關類和ADO類庫簡介  
          1)單獨使用CRecordSet  
          一般情況下AppWizard會在數據庫應用程序中自動產生CRecordset的派生類,并將派生類和某個數據源中的表聯系起來也可以和視圖上的子窗口聯系起來。但是有時這樣做會影響到程序的靈活性,這時候我們可以單獨使用CRecordSet類。利用CRecordSet類我們可以執行SQL語句,并可以讀出結果集中數據。    
   
  首先我們需要包含頭文件afxdb.h,可以將#include   添加到stdafx.h文件中。此外在使用CRecordset時必須有一個又一個CDatabase對象,該對象的作用是管理數據源連接。然后可以產生一個CRecordset對象,利用BOOL   CRecordset::Open(   UINT   nOpenType   =   AFX_DB_USE_DEFAULT_TYPE,   LPCTSTR   lpszSQL   =   NULL,   DWORD   dwOptions   =   none   )可以執行SQL語句。  
   
  但執行成功后,可以調用以下的函數滾動光標,讀取數據。  
   
  MoveFirst   移動光標到第一條記錄處    
  MoveNext   移動光標到后一條記錄處    
  MovePrev   移動光標到前一條記錄處    
  MoveLast   移動光標到最后一條記錄處    
  IsBOF   檢測光標是否在第一條記錄上    
  IsEOF   檢測光標是否在最后一條記錄上    
  GetFieldValue   得到結果中數據    
   
  下面是具體代碼:  
  /*  
  假設CDatabase   m_dbConn為成員變量  
  假設有一個表有如下SQL語句產生:CREATE   TABLE   table1(loc_id   not   null)  
  */  
  void   CYourClass::ConnectToDB()  
  {//連接數據庫  
          BOOL   fOK   =   m_dbConn.Open("test");  
          TRACE("connect   fOK=%d\n",m_dbConn);  
  }    
  void   CYourClass::Select()  
  {//執行SELECT語句  
          CRecordset   rec(&m_dbConn);  
          BOOL   fOK   =   rec.Open(CRecordset::forwardOnly,"select   loc_id   from   table1   order   by   loc_id");  
          TRACE("select   fOK   =   %d\n",fOK);  
          TRACE("返回的列數為:%d\n",rec.GetRowsetSize());  
          CString   szResult;  
          while(!rec.IsEOF())  
          {  
                      rec.GetFieldValue((int)0,szResult);  
                      rec.MoveNext();  
                      TRACE("fetch   :   %s\n",szResult);  
            }  
  }  
     
  此外CRecordset::GetFieldValue有很多種原型,你可以通過指定列位置或是字段名來獲取數據:  
   
  void   GetFieldValue(   LPCTSTR   lpszName,   CDBVariant&   varValue,   short   nFieldType   =   DEFAULT_FIELD_TYPE   );  
   
  void   GetFieldValue(   short   nIndex,   CDBVariant&   varValue,   short   nFieldType   =   DEFAULT_FIELD_TYPE   );  
   
  void   GetFieldValue(   LPCTSTR   lpszName,   CString&   strValue   );  
   
  void   GetFieldValue(   short   nIndex,   CString&   strValue   );    
   
  如果使用CDBVariant類型變量來獲取結果,你可以得到任何類型的結果。在CDBVariant::m_dwType成員變量中記錄了該變量所包含的數據類型,根據該變量的值你可以確定數據類型并引用CDBVariant對象中的相應成員變量。

2)vc數據庫編程中CDatabase類的用法簡介  
      要建立與數據源的連接,首先應構造一個CDatabase對象,然后再調用CDatabase的Open成員函數.Open函數負責建立連接,其聲明為  
   
  virtual   BOOL   Open(   LPCTSTR   lpszDSN,   BOOL   bExclusive   =   FALSE,   BOOL   bReadOnly   =   FALSE,   LPCTSTR   lpszConnect   =   “ODBC;”,   BOOL   bUseCursorLib   =   TRUE   );   throw(   CDBException,   CMemoryException   );  
   
    參數lpszDSN指定了數據源名(構造數據源的方法將在后面介紹),在lpszConnect參數中也可包括數據源名,此時lpszDSN必需為NULL,若在函數中未提供數據源名且使lpszDSN為NULL,則會顯示一個數據源對話框,用戶可以在該對話框中選擇一個數據源.參數bExclusive說明是否獨占數據源,由于目前版本的類庫還不支持獨占方式,故該參數的值應該是FALSE,這說明數據源是被共享的.參數bReadOnly若為TRUE則對數據源的連接是只讀的.參數lpszConnect指定了一個連接字符串,連接字符串中可以包括數據源名、用戶帳號(ID)和口令等信息,字符串中的"ODBC"表示要連接到一個ODBC數據源上.參數bUseCursorLib若為TRUE,則會裝載光標庫,否則不裝載,快照需要光標庫,動態集不需要光標庫.   若連接成功,函數返回TRUE,若返回FALSE,則說明用戶在數據源對話框中按了Cancel按鈕。若函數內部出現錯誤,則框架會產生一個異常。  
   
    下面是一些調用Open函數的例子。  
   
  CDatabase   m_db;   //在文檔類中嵌入一個CDatabase對象  
   
  //連接到一個名為"Student   Registration"的數據源  
   
  m_db.Open("Student   Registration");    
   
  //在連接數據源的同時指定了用戶帳號和口令  
   
  m_db.Open(NULL,FALSE,FALSE,"ODBC;DSN=Student   Registration;UID=ZYF;PWD=1234");  
  m_db.Open(NULL);   //將彈出一個數據源對話框  
     
   
    要從一個數據源中脫離,可調用函數Close。在脫離后,可以再次調用Open函數來建立一個新的連接.調用IsOpen可判斷當前是否有一個連接,調用GetConnect可返回當前的連接字符串。函數的聲明為  
   
  virtual   void   Close(   );  
  BOOL   IsOpen(   )   const;   //返回TRUE則表明當前有一個連接  
  const   CString&   GetConnect(   )   const;  
   
    CDatabase的析構函數會調用Close,所以只要刪除了CDatabase對象就可以與數據源脫離。

3)vc數據庫編程中CRecordView類簡介  
          CRecordView(記錄視圖)是CFormView的派生類,它提供了一個表單視圖來顯示當前記錄.用戶可以通過表單視圖顯示當前記錄.通過記錄視圖,可以修改、添加和刪除數據.用戶一般需要創建一個CRecordView的派生類并在其對應的對話框模板中加入控件.  
          記錄視圖使用DDX數據交換機制在表單中的控件和記錄集之間交換數據。在前面介紹的DDX都是在控件和控件父窗口的數據成員之間交換數據,而記錄視圖則是在控件和一個外部對象(CRecordset的派生類對象)之間交換數據.清單10.3顯示了一個CRecordView的派生類的DoDataExchange函數,讀者可以看出,該函數是與m_pSet指針指向的記錄集對象的域數據成員交換數據的,而且,交換數據的代碼是ClassWizard自動加入的.在后面的例子中,將向讀者介紹用ClassWizard連接記錄視圖與記錄集對象的方法.  
   
        用來與記錄集對象的域數據成員交換數據的DoDataExchange函數  
   
  void   CSectionForm::DoDataExchange(CDataExchange*   pDX)  
  {  
          CRecordView::DoDataExchange(pDX);  
  //{{AFX_DATA_MAP(CSectionForm)  
          DDX_FieldText(pDX,   IDC_COURSE,   m_pSet->m_CourseID,   m_pSet);  
          DDX_FieldText(pDX,   IDC_SECTION,   m_pSet->m_SectionNo,   m_pSet);  
          DDX_FieldText(pDX,   IDC_INSTRUCTOR,   m_pSet->m_InstructorID,   m_pSet);  
          DDX_FieldText(pDX,   IDC_ROOM,   m_pSet->m_RoomNo,   m_pSet);  
          DDX_FieldText(pDX,   IDC_SCHEDULE,   m_pSet->m_Schedule,   m_pSet);  
          DDX_FieldText(pDX,   IDC_CAPACITY,   m_pSet->m_Capacity,   m_pSet);  
  //}}AFX_DATA_MAP  
  }  
   
  CRecordView本身提供了對下面四個命令的支持:  
   
  ID_RECORD_FIRST   //滾動到記錄集的第一個記錄  
  ID_RECORD_LAST   //滾動到記錄集的最后一個記錄  
  ID_RECORD_NEXT   //前進一個記錄  
  ID_RECORD_PREV   //后退一個記錄  
   
  CRecordView提供了OnMove成員函數處理這四個命令消息,OnMove函數對用戶是透明的,下面列出了OnMove的源代碼.  
   
  BOOL   CRecordView::OnMove(UINT   nIDMoveCommand)  
  {  
          CRecordset*   pSet   =   OnGetRecordset();  
          if   (pSet->CanUpdate())  
          {  
                    pSet->Edit();  
                    if   (!UpdateData())  
                              return   TRUE;  
                    pSet->Update();  
            }  
            switch   (nIDMoveCommand)  
          {  
          case   ID_RECORD_PREV:  
                    pSet->MovePrev();  
                    if   (!pSet->IsBOF())  
                            break;  
          case   ID_RECORD_FIRST:  
                    pSet->MoveFirst();  
                    break;  
          case   ID_RECORD_NEXT:  
                    pSet->MoveNext();  
                    if   (!pSet->IsEOF())  
                            break;  
                    if   (!pSet->CanScroll())  
                    {  
                    //   clear   out   screen   since   we're   sitting   on   EOF  
                            pSet->SetFieldNull(NULL);  
                            break;    
                    }  
            case   ID_RECORD_LAST:  
                      pSet->MoveLast();  
                      break;  
            default:  
            //   Unexpected   case   value  
                      ASSERT(FALSE);  
  }  
  //   Show   results   of   move   operation  
          UpdateData(FALSE);  
          return   TRUE;  
  }  
        在函數的開頭先調用CRecordset::Edit進入編輯模式,接著調用UpdateData將控件中的數據更新到記錄集對象的域數據成員中,然后調用CRecordset::Update將域數據成員的值寫入數據源.這說明OnMove在滾動記錄的同時會完成對原來記錄的修改.  
   
    在函數的中間有一個分支語句用來處理四個不同的命令,在這個分支語句中調用了CRecordset的各種用于滾動記錄的成員函數,這些函數在滾動到一個新的記錄時會把該記錄的內容設置到域數據成員中.在函數的末尾調用UpdateData(FALSE)把新的當前記錄的內容設置到表單的控件中。  
   
    由此可見,OnMove一來一回完成了兩次表單控件和數據源的數據交換過程.通過分析該函數,讀者可以學會在瀏覽記錄時如何控制DDX和DFX數據交換.
posted on 2009-07-20 11:16 Bluesea 閱讀(1007) 評論(0)  編輯 收藏 引用 所屬分類: MFC
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美一区二区三区久久精品茉莉花| 亚洲国产精品va在看黑人| 亚洲国产精品久久久久| 亚洲精选国产| 国产精品久久久久久久久借妻| 欧美一级一区| 老司机aⅴ在线精品导航| 亚洲夜晚福利在线观看| 久久国产精品99国产精| 亚洲精品一级| 亚洲欧美综合一区| 亚洲欧洲一区二区天堂久久| 午夜亚洲福利在线老司机| 欧美一区二区在线视频| 久久夜色精品国产噜噜av| 欧美一区二区网站| 伊人色综合久久天天五月婷| 男人的天堂亚洲| 亚洲一区二区不卡免费| 亚洲人成网在线播放| 亚洲午夜精品福利| 国产一区二区三区精品欧美日韩一区二区三区 | 久久久综合香蕉尹人综合网| 欧美亚洲视频在线看网址| 亚洲女人av| 久久久噜噜噜久久中文字免| 亚洲高清二区| 亚洲欧美日本国产有色| 久久av一区二区三区漫画| 欧美大片一区二区三区| 国产日韩1区| 一区二区三区四区国产| 午夜精品久久久久久久久久久| 免费观看成人| 午夜在线一区| 国产精品高潮呻吟| 亚洲高清二区| 欧美一区二区三区男人的天堂| 欧美激情一区在线| 欧美一区=区| 国产精品手机在线| 9久re热视频在线精品| 欧美99在线视频观看| 亚洲欧美激情诱惑| 欧美日韩国产成人在线| 亚洲高清av在线| 久久人人97超碰精品888| 99pao成人国产永久免费视频| 久久乐国产精品| 国产午夜精品久久久| 亚洲欧美日韩专区| 日韩一区二区精品| 欧美成人网在线| 妖精视频成人观看www| 玖玖玖国产精品| 亚洲一区二区精品| 国产精品乱人伦中文| 亚洲视频在线观看视频| 亚洲电影一级黄| 快she精品国产999| 在线播放豆国产99亚洲| 久久久久久久久久久久久9999| 亚洲一区二区三区免费视频| 欧美日韩国产首页在线观看| 亚洲精品日韩久久| 欧美激情成人在线| 欧美成人蜜桃| 一区二区国产在线观看| 99视频国产精品免费观看| 欧美精品自拍| 亚洲一本视频| 午夜精品一区二区三区在线视 | 噜噜噜在线观看免费视频日韩| 久久精彩免费视频| 亚洲福利精品| 亚洲黄色天堂| 国产精品免费一区二区三区观看| 欧美在线free| 久久久久久久久久久久久久一区 | 亚洲精品美女免费| 亚洲二区免费| 国产精品成av人在线视午夜片 | 亚洲午夜精品久久| 国产日韩在线视频| 欧美华人在线视频| 欧美日韩久久| 久久一二三区| 欧美日韩成人| 久久最新视频| 欧美无乱码久久久免费午夜一区 | 在线综合亚洲| 国内视频一区| 亚洲精品日韩激情在线电影| 国产精品日韩一区二区| 久久综合99re88久久爱| 欧美日韩国产123| 久久亚洲美女| 午夜精品福利一区二区三区av| 欧美伊人精品成人久久综合97 | 久久狠狠婷婷| 老司机一区二区| 91久久夜色精品国产九色| 亚洲日本欧美天堂| 国产欧美日韩高清| 亚洲激情国产精品| 国产伦精品一区二区三区视频孕妇 | 一区二区欧美在线| 亚洲欧美一级二级三级| 亚洲国产日韩欧美在线图片| 亚洲影院色无极综合| 亚洲人成在线观看网站高清| 亚洲性视频h| 亚洲三级毛片| 久久琪琪电影院| 欧美综合国产精品久久丁香| 欧美激情一区在线观看| 久久久久国产精品午夜一区| 欧美午夜免费电影| 亚洲激情中文1区| 激情欧美一区二区| 久久综合亚州| 亚洲欧美激情精品一区二区| 午夜亚洲性色福利视频| 亚洲国产精品激情在线观看| 欧美在线免费观看视频| 欧美一区深夜视频| 牛牛影视久久网| 国产日韩欧美在线一区| 亚洲伦理中文字幕| 亚洲精品偷拍| 久久亚裔精品欧美| 久久夜色精品国产欧美乱极品| 国产欧美日韩亚洲一区二区三区| 亚洲毛片在线观看.| 99精品国产99久久久久久福利| 欧美不卡高清| 亚洲激情在线激情| 在线免费观看欧美| 欧美一区二区三区免费看 | 亚洲欧洲精品一区二区三区波多野1战4| 亚洲欧美日韩成人高清在线一区| 亚洲无线视频| 国产精品萝li| 欧美一二三视频| 久久夜色精品国产噜噜av| 国产一区二区三区直播精品电影| 欧美一区二区免费观在线| 久久久久国产精品麻豆ai换脸| 国产亚洲欧美aaaa| 欧美在线亚洲一区| 久久亚洲国产成人| 91久久精品国产91性色| 欧美理论视频| 亚洲综合二区| 美女主播精品视频一二三四| 亚洲电影下载| 欧美日韩国产一区二区| 亚洲一区二区精品在线| 久久偷看各类wc女厕嘘嘘偷窃| 亚洲黄色成人久久久| 欧美日韩高清在线| 亚洲欧美日韩中文在线制服| 巨胸喷奶水www久久久免费动漫| 亚洲精品乱码久久久久久蜜桃麻豆| 欧美日韩视频不卡| 欧美在线高清视频| 久久狠狠婷婷| 欧美国产日本| 欧美激情麻豆| 亚洲一级黄色片| 国内综合精品午夜久久资源| 欧美xart系列高清| 中国成人黄色视屏| 久久久亚洲精品一区二区三区| 亚洲日本成人| 国产精品久久久久国产精品日日| 久久精品最新地址| 一区二区毛片| 美国三级日本三级久久99| 一区二区三区精品视频在线观看 | 久久中文精品| 国产精品亚洲精品| 久久亚洲私人国产精品va| aa级大片欧美| 亚洲电影av| 欧美一区二区三区在线观看视频| 亚洲韩国一区二区三区| 国产精品久久久久秋霞鲁丝| 免费成人av在线| 欧美一区二区三区在线视频| 99国产麻豆精品| 欧美大胆a视频| 久久精品一区中文字幕| 亚洲午夜激情网站| 国产精品激情| 久久综合狠狠综合久久综合88 | 黄色国产精品| 免费观看日韩| 久久国产精品72免费观看| 99精品国产一区二区青青牛奶|