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

隨筆-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>
            欧美综合激情网| 久久在线精品| 国产精品亚洲第一区在线暖暖韩国| 欧美.com| 欧美大片在线影院| 欧美日本一区二区视频在线观看| 欧美精品v国产精品v日韩精品| 欧美一区二区三区视频免费| 欧美一级久久久久久久大片| 欧美一区二区大片| 免费在线成人| 亚洲免费观看视频| 亚洲一区二区三区精品动漫| 久久xxxx| 欧美黄色一级视频| 国产人成精品一区二区三| 亚洲第一综合天堂另类专| 一区二区国产日产| 久久久国产视频91| 亚洲精品在线免费观看视频| 西西人体一区二区| 欧美激情片在线观看| 国产噜噜噜噜噜久久久久久久久| 在线观看国产成人av片| 亚洲小说欧美另类社区| 久久亚洲色图| 亚洲精品在线观看免费| 久久久精品一区二区三区| 欧美日韩免费观看中文| 精品99一区二区三区| 亚洲女ⅴideoshd黑人| 欧美高清视频一区二区| 亚洲欧美伊人| 欧美午夜不卡视频| 亚洲精品久久视频| 久久亚洲高清| 亚洲男同1069视频| 欧美日韩视频专区在线播放 | 亚洲三级毛片| 亚洲欧美日韩一区二区三区在线观看 | 欧美日本免费一区二区三区| 红桃视频国产精品| 性欧美videos另类喷潮| 99v久久综合狠狠综合久久| 噜噜噜躁狠狠躁狠狠精品视频 | 免费久久99精品国产| 国产日韩精品一区二区| 亚洲一区三区视频在线观看| 亚洲青涩在线| 欧美大色视频| 亚洲精品色图| 亚洲福利视频三区| 免费观看成人www动漫视频| 伊人久久综合| 蜜桃久久av一区| 久久裸体艺术| 久久99伊人| 国产专区欧美专区| 久久综合成人精品亚洲另类欧美| 香蕉久久a毛片| 国产亚洲精品成人av久久ww| 欧美专区福利在线| 欧美一区二区视频在线观看| 国产欧美精品在线播放| 欧美在线观看一区| 久久av一区二区三区亚洲| 国产原创一区二区| 免费在线视频一区| 免费影视亚洲| 亚洲色诱最新| 香蕉精品999视频一区二区| 国产专区欧美精品| 亚洲第一综合天堂另类专| 欧美fxxxxxx另类| 日韩午夜在线视频| 9i看片成人免费高清| 国产精品日韩欧美大师| 欧美在线视频a| 久久亚洲精品网站| 日韩亚洲欧美在线观看| 一区二区高清| 国产一区二区三区在线观看精品 | 亚洲中无吗在线| 国产视频不卡| 亚洲电影免费观看高清完整版在线| 欧美成人中文字幕| 宅男精品视频| 欧美在线亚洲在线| 亚洲精品在线一区二区| 亚洲午夜av| 在线观看精品视频| 日韩网站免费观看| 国产一区二区三区四区hd| 亚洲成人直播| 国产九九视频一区二区三区| 欧美韩国日本一区| 国产精品亚洲精品| 亚洲大胆人体视频| 国产精品无码永久免费888| 麻豆成人在线播放| 国产精品成人aaaaa网站| 久久久亚洲一区| 欧美午夜不卡在线观看免费| 欧美成人精品在线播放| 国产精品女人网站| 亚洲激情电影在线| 国内伊人久久久久久网站视频 | 9l视频自拍蝌蚪9l视频成人| 韩国在线一区| 在线亚洲自拍| 欧美日韩国产免费| 久久理论片午夜琪琪电影网| 欧美日韩一区免费| 欧美高清在线观看| 国产综合婷婷| 午夜久久美女| 亚洲欧美精品一区| 欧美日韩免费在线观看| 欧美成人有码| 一区二区三区在线高清| 午夜精品婷婷| 亚洲欧美日韩精品久久久| 欧美国产精品劲爆| 久久综合久久综合这里只有精品| 国产精品一二| 一区二区三区欧美成人| 一本一道久久综合狠狠老精东影业| 久久精品一区二区国产| 久久精品五月婷婷| 国产精品久久久久一区二区三区共 | 国产日本欧美一区二区| 一区二区三区国产在线| 亚洲美女啪啪| 欧美理论电影在线观看| 亚洲激情第一区| 日韩视频在线一区二区| 欧美插天视频在线播放| 亚洲成人在线视频播放 | 亚洲国产裸拍裸体视频在线观看乱了中文| 亚洲深夜激情| 性欧美大战久久久久久久久| 国产精品久久久久天堂| 亚洲欧美日韩精品久久| 午夜一级在线看亚洲| 国产精品久久久免费| 亚洲尤物在线| 久久久久久穴| 亚洲成人原创| 欧美另类视频| 亚洲一区视频| 久久婷婷国产综合国色天香| 精品999成人| 欧美国产一区二区三区激情无套| 亚洲大胆av| 亚洲天堂av在线免费| 国产精品日韩精品欧美精品| 久久aⅴ国产欧美74aaa| 欧美成人按摩| 一区二区三区 在线观看视| 国产精品久久久久久久第一福利 | 狠狠久久五月精品中文字幕| 久久久久这里只有精品| 最新中文字幕一区二区三区| 亚洲淫片在线视频| 国产亚洲欧美另类中文| 欧美高清在线视频| 亚洲自拍偷拍福利| 另类图片国产| 欧美视频中文在线看 | 亚洲国产中文字幕在线观看| 欧美久久久久免费| 午夜精品久久久久久久| 久久综合色影院| 中日韩男男gay无套| 狠狠色综合播放一区二区| 欧美高清视频免费观看| 欧美在线观看日本一区| 亚洲激情国产精品| 久久国产视频网| 亚洲片在线资源| 国产精品久久久久久久第一福利| 免费中文日韩| 欧美一区二区三区四区在线观看地址| 亚洲福利国产| 欧美激情1区2区3区| 亚洲视频中文| 噜噜噜91成人网| 亚洲一区视频在线| 在线观看中文字幕亚洲| 国产精品久久久久久久久搜平片 | 亚洲精品国产精品国自产在线| 亚洲欧美中文另类| 亚洲成色777777女色窝| 国产精品欧美久久久久无广告| 免费黄网站欧美| 久久久久久一区二区三区| 一区二区三区高清视频在线观看| 欧美1区视频| 久久一区亚洲| 久久久久久有精品国产|