一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

MFC的數(shù)據(jù)庫操作

 guitarhua 2011-08-22

MFC的數(shù)據(jù)庫操作  

2009-06-03 22:55:48|  分類: 默認(rèn)分類 |  標(biāo)簽: |字號 訂閱

 

1、 MFCODBC類簡介

  MFC的ODBC類對較復(fù)雜的ODBC API進(jìn)行了封裝,提供了簡化的調(diào)用接口,從而大大方便了數(shù)據(jù)庫應(yīng)用程序的開發(fā)。程序員不必了解ODBC API和SQL的具體細(xì)節(jié),利用ODBC類即可完成對數(shù)據(jù)庫的大部分操作。

  MFC的ODBC類主要包括:

CDatabase類:主要功能是建立與數(shù)據(jù)源的連接。

CRecordset類:該類代表從數(shù)據(jù)源選擇的一組記錄(記錄集),程序可以選擇數(shù)據(jù)源中的某個(gè)表作為一個(gè)記錄集,也可以通過對表的查詢得到記錄集,還可以合并同一數(shù)據(jù)源中多個(gè)表的列到一個(gè)記錄集中.通過該類可對記錄集中的記錄進(jìn)行滾動、修改、增加和刪除等操作。

CRecordView類:提供了一個(gè)表單視圖與某個(gè)記錄集直接相連,利用對話框數(shù)據(jù)交換機(jī)制(DDX)在記錄集與表單視圖的控件之間傳輸數(shù)據(jù)。該類支持對記錄的瀏覽和更新,在撤銷時(shí)會自動關(guān)閉與之相聯(lián)系的記錄集。

CFieldExchange類:支持記錄字段數(shù)據(jù)交換(DFX),即記錄集字段數(shù)據(jù)成員與相應(yīng)的數(shù)據(jù)庫的表的字段之間的數(shù)據(jù)交換。該類的功能與CDataExchange類的對話框數(shù)據(jù)交換功能類似。

CDBException類:代表ODBC類產(chǎn)生的異常。

  概括地講,CDatabase針對某個(gè)數(shù)據(jù)庫,它負(fù)責(zé)連接數(shù)據(jù)源;CRecordset針對數(shù)據(jù)源中的記錄集,它負(fù)責(zé)對記錄的操作;CRecordView負(fù)責(zé)界面,而CFieldExchange負(fù)責(zé)CRecordset與數(shù)據(jù)源的數(shù)據(jù)交換。

  利用AppWizard和ClassWizard,用戶可以方便地建立數(shù)據(jù)庫應(yīng)用程序,但這并不意味著可以對MFC的ODBC類一無所知.讀者應(yīng)注意閱讀后面幾小節(jié)中的內(nèi)容,為學(xué)習(xí)后面的例子打好基礎(chǔ).

2、 CDatabase

  要建立與數(shù)據(jù)源的連接,首先應(yīng)構(gòu)造一個(gè)CDatabase對象,然后再調(diào)用CDatabase的Open成員函數(shù).Open函數(shù)負(fù)責(zé)建立連接,其聲明為

virtual BOOL Open( LPCTSTR lpszDSN, BOOL bExclusive = FALSE, BOOL bReadOnly = FALSE, LPCTSTR lpszConnect = “ODBC;”, BOOL bUseCursorLib = TRUE ); throw( CDBException, CMemoryException );

   參數(shù)lpszDSN指定了數(shù)據(jù)源名(構(gòu)造數(shù)據(jù)源的方法將在后面介紹),在lpszConnect參數(shù)中也可包括數(shù)據(jù)源名,此時(shí)lpszDSN必需為 NULL,若在函數(shù)中未提供數(shù)據(jù)源名且使lpszDSN為NULL,則會顯示一個(gè)數(shù)據(jù)源對話框,用戶可以在該對話框中選擇一個(gè)數(shù)據(jù)源.參數(shù) bExclusive說明是否獨(dú)占數(shù)據(jù)源,由于目前版本的類庫還不支持獨(dú)占方式,故該參數(shù)的值應(yīng)該是FALSE,這說明數(shù)據(jù)源是被共享的.參數(shù) bReadOnly若為TRUE則對數(shù)據(jù)源的連接是只讀的.參數(shù)lpszConnect指定了一個(gè)連接字符串,連接字符串中可以包括數(shù)據(jù)源名、用戶賬號 (ID)和口令等信息,字符串中的"ODBC"表示要連接到一個(gè)ODBC數(shù)據(jù)源上.參數(shù)bUseCursorLib若為TRUE,則會裝載光標(biāo)庫,否則不 裝載,快照需要光標(biāo)庫,動態(tài)集不需要光標(biāo)庫. 若連接成功,函數(shù)返回TRUE,若返回FALSE,則說明用戶在數(shù)據(jù)源對話框中按了Cancel按鈕。若函數(shù)內(nèi)部出現(xiàn)錯(cuò)誤,則框架會產(chǎn)生一個(gè)異常。

  下面是一些調(diào)用Open函數(shù)的例子。

CDatabase m_db; //在文檔類中嵌入一個(gè)CDatabase對象

//連接到一個(gè)名為"Student Registration"的數(shù)據(jù)源

m_db.Open("Student Registration");

//在連接數(shù)據(jù)源的同時(shí)指定了用戶賬號和口令

m_db.Open(NULL,FALSE,FALSE,"ODBC;DSN=Student Registration;UID=ZYF;PWD=1234");

m_db.Open(NULL); //將彈出一個(gè)數(shù)據(jù)源對話框

 

  要從一個(gè)數(shù)據(jù)源中脫離,可調(diào)用函數(shù)Close。在脫離后,可以再次調(diào)用Open函數(shù)來建立一個(gè)新的連接.調(diào)用IsOpen可判斷當(dāng)前是否有一個(gè)連接,調(diào)用GetConnect可返回當(dāng)前的連接字符串。函數(shù)的聲明為

virtual void Close( );

BOOL IsOpen( ) const; //返回TRUE則表明當(dāng)前有一個(gè)連接

const CString& GetConnect( ) const;

  CDatabase的析構(gòu)函數(shù)會調(diào)用Close,所以只要?jiǎng)h除了CDatabase對象就可以與數(shù)據(jù)源脫離。

3、CRecordset

  CRecordset類代表一個(gè)記錄集.該類是MFC的ODBC類中最重要、功能最強(qiáng)大的類。

10.5.1 動態(tài)集、快照、光標(biāo)和光標(biāo)庫

   在多任務(wù)操作系統(tǒng)或網(wǎng)絡(luò)環(huán)境中,多個(gè)用戶可以共享同一個(gè)數(shù)據(jù)源。共享數(shù)據(jù)的一個(gè)主要問題是如何協(xié)調(diào)各個(gè)用戶對數(shù)據(jù)源的修改。例如,當(dāng)某一個(gè)應(yīng)用改變了數(shù) 據(jù)源中的記錄時(shí),別的連接至該數(shù)據(jù)源的應(yīng)用應(yīng)該如何處理。對于這個(gè)問題,基于MFC的ODBC應(yīng)用程序可以采取幾種不同的處理辦法,這將由程序采用哪種記 錄集決定。

  記錄集主要分為快照(Snapshot) 和動態(tài)集(Dynaset)兩種,CRecordset類對這兩者都支持。這兩種記錄集的不同表現(xiàn)在它們對別的應(yīng)用改變數(shù)據(jù)源記錄采取了不同的處理方法。

   快照型記錄集提供了對數(shù)據(jù)的靜態(tài)視.快照是個(gè)很形象的術(shù)語,就好象對數(shù)據(jù)源的某些記錄照了一張照片一樣.當(dāng)別的用戶改變了記錄時(shí)(包括修改、添加和刪 除),快照中的記錄不受影響,也就是說,快照不反映別的用戶對數(shù)據(jù)源記錄的改變.直到調(diào)用了CRecordset::Requery重新查詢后,快照才會 反映變化.對于象產(chǎn)生報(bào)告或執(zhí)行計(jì)算這樣的不希望中途變動的工作,快照是很有用的。需要指出的是,快照的這種靜態(tài)特性是相對于別的用戶而言的,它會正確反 映由本身用戶對記錄的修改和刪除,但對于新添加的記錄直到調(diào)用Requery后才能反映到快照中.

   動態(tài)集提供了數(shù)據(jù)的動態(tài)視.當(dāng)別的用戶修改或刪除了記錄集中的記錄時(shí),會在動態(tài)集中反映出來:當(dāng)滾動到修改過的記錄時(shí)對其所作的修改會立即反映到動態(tài)集 中,當(dāng)記錄被刪除時(shí),MFC代碼會跳過記錄集中的刪除部分.對于其它用戶添加的記錄,直到調(diào)用Requery時(shí),才會在動態(tài)集中反映出來。本身應(yīng)用程序?qū)?記錄的修改、添加和刪除會反映在動態(tài)集中。當(dāng)數(shù)據(jù)必須是動態(tài)的時(shí)侯,使用動態(tài)集是最適合的。例如,在一個(gè)火車票聯(lián)網(wǎng)售票系統(tǒng)中,顯然應(yīng)該用動態(tài)集隨時(shí)反映 出共享數(shù)據(jù)的變化。

  在記錄集中滾動,需要有一個(gè)標(biāo)志來指明滾動后的位置(當(dāng)前位置)。ODBC驅(qū)動程序會維護(hù)一個(gè)光標(biāo),用來跟蹤記錄集的當(dāng)前記錄,可以把光標(biāo)理解成跟蹤記錄集位置的一種機(jī)制。

   光標(biāo)庫(Cursor Library)是處于ODBC驅(qū)動程序管理器和驅(qū)動程序之間的動態(tài)鏈接庫(ODBCCR32.DLL).光標(biāo)庫的主要功能是支持快照以及為底層驅(qū)動程序 提供雙向滾動能力,高層次的驅(qū)動程序不需要光標(biāo)庫,因?yàn)樗鼈兪强蓾L動的.光標(biāo)庫管理快照記錄的緩沖區(qū),該緩沖區(qū)反映本程序?qū)τ涗浀男薷暮蛣h除,但不反映其 它用戶對記錄的改變,由此可見,快照實(shí)際上相當(dāng)于當(dāng)前的光標(biāo)庫緩沖區(qū).

  應(yīng)注 意的是,快照是一種靜態(tài)光標(biāo)(Static Cursor).靜態(tài)光標(biāo)直到滾動到某個(gè)記錄才能取得該記錄的數(shù)據(jù).因此,要保證所有的記錄都被快照,可以先滾動到記錄集的末尾,然后再滾動到感興趣的第 一個(gè)記錄上.這樣做的缺點(diǎn)是滾動到末尾需要額外的開銷,會降低性能.

  與快照不同,動態(tài)集不用光標(biāo)庫維持的緩沖區(qū)來存放記錄.實(shí)際上,動態(tài)集是不使用光標(biāo)庫的,因?yàn)楣鈽?biāo)庫會屏蔽掉一些支持動態(tài)集的底層驅(qū)動程序功能.動態(tài)集是一種鍵集驅(qū)動光標(biāo)(Keyset-Driven Cursor),當(dāng)打開一個(gè)動態(tài)集時(shí),驅(qū)動程序保存記錄集中每個(gè)記錄的鍵.只要光標(biāo)在動態(tài)集中滾動,驅(qū)動程序就會通過鍵來從數(shù)據(jù)源中檢取當(dāng)前記錄,從而保證選取的記錄與數(shù)據(jù)源同步.

  從上面的分析中可以看出,快照和動態(tài)集有一個(gè)共同的特點(diǎn),那就是在建立記錄集后,記錄集中的成員就已經(jīng)確定了.這就是為什么兩種記錄集都不能反映別的用戶添加記錄的原因.

10.5.2 域數(shù)據(jù)成員與數(shù)據(jù)交換

   CRecordset類代表一個(gè)記錄集.用戶一般需要用ClassWizard創(chuàng)建一個(gè)CRecordset的派生類.ClassWizard可以為派 生的記錄集類創(chuàng)建一批數(shù)據(jù)成員,這些數(shù)據(jù)成員與記錄的各字段相對應(yīng),被稱為字段數(shù)據(jù)成員或域數(shù)據(jù)成員.例如,對于表10.2所示的將在后面例子中使用的數(shù) 據(jù)庫表,ClassWizard會在派生類中加入6個(gè)域數(shù)據(jù)成員,如清單10.1所示.可以看出域數(shù)據(jù)成員與表中的字段名字類似,且類型匹配.

 

表10.2 stdreg32.mdb中的Section表

CourseID

(Text)

SectionNo

(Text)

InstructorID

(Text)

RoomNo

(Text)

Schedule

(Text)

Capacity

(int)

MATH101

1

KLAUSENJ

KEN-12

MWF10-11

40

MATH101

2

ROGERSN

WIL-1088

TTH3:30-5

15

MATH201

1

ROGERSN

WIL-1034

MWF2-3

20

MATH201

2

SMITHJ

WIL-1054

MWF3-4

25

MATH202

1

KLA

WIL-1054

MWF9-10

20

MATH202

2

ROGERSN

KEN-12

TTH9:30-11

15

MATH202

3

KLAUSENJ

WIL-2033

TTH3-4:30

15

清單10.1 派生類中的域數(shù)據(jù)成員

class CSectionSet : public CRecordset

{

public:

. . . . . .

//{{AFX_FIELD(CSectionSet, CRecordset)

CString m_CourseID;

CString m_SectionNo;

CString m_InstructorID;

CString m_RoomNo;

CString m_Schedule;

int m_Capacity;

//}}AFX_FIELD

. . . . . .

};

 

   域數(shù)據(jù)成員用來保存某條記錄的各個(gè)字段,它們是程序與記錄之間的緩沖區(qū).域數(shù)據(jù)成員代表當(dāng)前記錄,當(dāng)在記錄集中滾動到某一記錄時(shí),框架自動地把記錄的各 個(gè)字段拷貝到記錄集對象的域數(shù)據(jù)成員中.當(dāng)用戶要修改當(dāng)前記錄或增加新記錄時(shí),程序先將各字段的新值放入域數(shù)據(jù)成員中,然后調(diào)用相應(yīng)的 CRecordset成員函數(shù)把域數(shù)據(jù)成員設(shè)置到數(shù)據(jù)源中.

  不難看出,在記 錄集與數(shù)據(jù)源之間有一個(gè)數(shù)據(jù)交換問題.CRecordset類使用"記錄域交換"(Record Field Exchange,縮寫為RFX)機(jī)制自動地在域數(shù)據(jù)成員和數(shù)據(jù)源之間交換數(shù)據(jù).RFX機(jī)制與對話數(shù)據(jù)交換(DDX)類似.CRecordset的成員函 數(shù)DoFieldExchange負(fù)責(zé)數(shù)據(jù)交換任務(wù),在該函數(shù)中調(diào)用了一系列RFX函數(shù).當(dāng)用戶用ClassWizard加入域數(shù)據(jù)成員 時(shí),ClassWizard會自動在DoFieldExchange中建立RFX.典型DoFieldExchange如清單10.2所示:

清單10.2 典型的DoFieldExchange函數(shù)

void CSectionSet::DoFieldExchange(CFieldExchange* pFX)

{

//{{AFX_FIELD_MAP(CSectionSet)

pFX->SetFieldType(CFieldExchange::outputColumn);

RFX_Text(pFX, _T("[CourseID]"), m_CourseID);

RFX_Text(pFX, _T("[SectionNo]"), m_SectionNo);

RFX_Text(pFX, _T("[InstructorID]"), m_InstructorID);

RFX_Text(pFX, _T("[RoomNo]"), m_RoomNo);

RFX_Text(pFX, _T("[Schedule]"), m_Schedule);

RFX_Int(pFX, _T("[Capacity]"), m_Capacity);

//}}AFX_FIELD_MAP

}

 

 

10.5.3 SQL查詢

   記錄集的建立實(shí)際上主要是一個(gè)查詢過程,SQL的SELECT語句用來查詢數(shù)據(jù)源.在建立記錄集時(shí),CRecordset會根據(jù)一些參數(shù)構(gòu)造一個(gè) SELECT語句來查詢數(shù)據(jù)源,并用查詢的結(jié)果創(chuàng)建記錄集.明白這一點(diǎn)對理解CRecordset至關(guān)重要.SELECT語句的句法如下:

SELECT rfx-field-list FROM table-name [WHERE m_strFilter]

[ORDER BY m_strSort]

  其中table-name是表名,rfx-field-list是選擇的列(字段).WHERE和ORDER BY是兩個(gè)子句,分別用來過濾和排序。下面是SELECT語句的一些例子:

SELECT CourseID, InstructorID FROM Section

SELECT * FROM Section WHERE CourseID=‘MATH202’ AND Capacity=15

SELECT InstructorID FROM Section ORDER BY CourseID ASC

   其中第一個(gè)語句從Section表中選擇CourseID和InstructorID字段.第二個(gè)語句從Section表中選擇CourseID為 MATH202且Capacity等于15的記錄,在該語句中使用了象"AND"或"OR"這樣的邏輯連接符.要注意在SQL語句中引用字符串、日期或時(shí) 間等類型的數(shù)據(jù)時(shí)要用單引號括起來,而數(shù)值型數(shù)據(jù)則不用.第三個(gè)語句從Section表中選擇InstructorID列并且按CourseID的升序排 列,若要降序排列,可使用關(guān)鍵字DESC.

提示:如果列名或表名中包含有空格,則必需用方括號把該名稱包起來。例如,如果有一列名為“Client Name”,則應(yīng)該寫成“[Client Name]”。

 

10.5.4 記錄集的建立和關(guān)閉

  要建立記錄集,首先要構(gòu)造一個(gè)CRecordset派生類對象,然后調(diào)用Open成員函數(shù)查詢數(shù)據(jù)源中的記錄并建立記錄集.在Open函數(shù)中,可能會調(diào)用GetDefaultConnect和GetDefaultSQL函數(shù).函數(shù)的聲明為

CRecordset( CDatabase* pDatabase = NULL);
參數(shù)pDatabase指向一個(gè)CDatabase對象,用來獲取數(shù)據(jù)源.如果pDatabase為NULL,則會在Open函數(shù)中自動構(gòu)建一個(gè) CDatabase對象.如果CDatabase對象還未與數(shù)據(jù)源連接,那么在Open函數(shù)中會建立連接,連接字符串(參見10.3.1)由成員函數(shù) GetDefaultConnect提供.

virtual CString GetDefaultConnect( );
該函數(shù)返回缺省的連接字符串.Open函數(shù)在必要的時(shí)侯會調(diào)用該函數(shù)獲取連接字符串以建立與數(shù)據(jù)源的連接.一般需要在CRecordset派生類中覆蓋該函數(shù)并在新版的函數(shù)中提供連接字符串.

virtual BOOL Open( UINT nOpenType = AFX_DB_USE_DEFAULT_TYPE, LPCTSTR lpszSQL = NULL, DWORD dwOptions = none );
throw( CDBException, CMemoryException );
該函數(shù)使用指定的SQL語句查詢數(shù)據(jù)源中的記錄并按指定的類型和選項(xiàng)建立記錄集.參數(shù)nOpenType說明了記錄集的類型,如表10.3所示,如果要求 的類型驅(qū)動程序不支持,則函數(shù)將產(chǎn)生一個(gè)異常.參數(shù)lpszSQL是一個(gè)SQL的SELECT語句,或是一個(gè)表名.函數(shù)用lpszSQL來進(jìn)行查詢,如果 該參數(shù)為NULL,則函數(shù)會調(diào)用GetDefaultSQL獲取缺省的SQL語句.參數(shù)dwOptions可以是一些選項(xiàng)的組合,常用的選項(xiàng)在表10.4 中列出.若創(chuàng)建成功則函數(shù)返回TRUE,若函數(shù)調(diào)用了CDatabase::Open且返回FALSE,則函數(shù)返回FALSE.

 

表10.3 記錄集的類型

類型

含義

AFX_DB_USE_DEFAULT_TYPE

使用缺省值.

CRecordset::dynaset

可雙向滾動的動態(tài)集.

CRecordset::snapshot

可雙向滾動的快照.

CRecordset::dynamic

提供比動態(tài)集更好的動態(tài)特性,大部分ODBC驅(qū)動程序不支持這種記錄集.

CRecordset::forwardOnly

只能前向滾動的只讀記錄集.

 

 

表10.4 創(chuàng)建記錄集時(shí)的常用選項(xiàng)

選項(xiàng)

含義

CRecordset::none

無選項(xiàng)(缺?。?/p>

CRecordset::appendOnly

不允許修改和刪除記錄,但可以添加記錄.

CRecordset::readOnly

記錄集是只讀的.

CRecordset::skipDeletedRecords

有些數(shù)據(jù)庫(如FoxPro)在刪除記錄時(shí)并不真刪除,而是做個(gè)刪除標(biāo)記,在滾動時(shí)將跳過這些被刪除的記錄.

 

 

virtual CString GetDefaultSQL( );
Open函數(shù)在必要時(shí)會調(diào)用該函數(shù)返回缺省的SQL語句或表名以查詢數(shù)據(jù)源中的記錄.一般需要在CRecordset派生類中覆蓋該函數(shù)并在新版的函數(shù)中提供SQL語句或表名.下面是一些返回字符串的例子.
“Section” //選擇Section表中的所有記錄到記錄集中
“Section, Course” //合并Section表和Course表的各列到記錄集中

//對Section表中的所有記錄按CourseID的升序進(jìn)行排序,然后建立記錄集

“SELECT * FROM Section ORDER BY CourseID ASC”

  上面的例子說明,通過合理地安排SQL語句和表名,Open函數(shù)可以十分靈活地查詢數(shù)據(jù)源中的記錄.用戶可以合并多個(gè)表的字段,也可以只選擇記錄中的某些字段,還可以對記錄進(jìn)行過濾和排序.

   上一小節(jié)說過,在建立記錄集時(shí),CRecordset會構(gòu)造一個(gè)SELECT語句來查詢數(shù)據(jù)源.如果在調(diào)用Open時(shí)只提供了表名,那么SELECT語 句還缺少選擇列參數(shù)rfx-field-list(參見10.5.3).框架規(guī)定,如果只提供了表名,則選擇列的信息從DoFieldExchange中 的RFX語句里提?。?,如果在調(diào)用Open時(shí)只提供了"Section"表名,那么將會構(gòu)造如下一個(gè)SELECT語句:

SELECT CourseID,SectionNo,InstructorID,RoomNo, Schedule,Capacity FROM Section

 

  建立記錄集后,用戶可以隨時(shí)調(diào)用Requery成員函數(shù)來重新查詢和建立記錄集.Requery有兩個(gè)重要用途:

  • 使記錄集能反映用戶對數(shù)據(jù)源的改變(參見10.5.1).

  • 按照新的過濾或排序方法查詢記錄并重新建立記錄集.

 

  在調(diào)用Requery之前,可調(diào)用CanRestart來判斷記錄集是否支持Requery操作.要記住Requery只能在成功調(diào)用Open后調(diào)用,所以程序應(yīng)調(diào)用IsOpen來判斷記錄集是否已建立.函數(shù)的聲明為

virtual BOOL Requery( );throw( CDBException, CMemoryException );
返回TRUE表明記錄集建立成功,否則返回FALSE.若函數(shù)內(nèi)部出錯(cuò)則產(chǎn)生異常.

BOOL CanRestart( ) const; //若支持Requery則返回TRUE

BOOL IsOpen( ) const; //若記錄集已建立則返回TRUE

   CRecordset類有兩個(gè)公共數(shù)據(jù)成員m_strFilter和m_strSort用來設(shè)置對記錄的過濾和排序.在調(diào)用Open或Requery 前,如果在這兩個(gè)數(shù)據(jù)成員中指定了過濾或排序,那么Open和Requery將按這兩個(gè)數(shù)據(jù)成員指定的過濾和排序來查詢數(shù)據(jù)源.

成員m_strFilter用于指定過濾器.m_strFilter實(shí)際上包含了SQL的WHERE子句的內(nèi)容,但它不含WHERE關(guān)鍵字.使用m_strFilter的一個(gè)例子為:

m_pSet->m_strFilter=“CourseID=‘MATH101’”; //只選擇CourseID為MATH101的記錄

if(m_pSet->Open(CRecordset::snapshot, “Section”))

. . . . . .

  成員m_strSort用于指定排序.m_strSort實(shí)際上包含了ORDER BY子句的內(nèi)容,但它不含ORDER BY關(guān)鍵字.m_strSort的一個(gè)例子為

m_pSet->m_strSort=“CourseID DESC”; //按CourseID的降序排列記錄

m_pSet->Open();

. . . . . .

  事實(shí)上,Open函數(shù)在構(gòu)造SELECT語句時(shí),會把m_strFilter和m_strSort的內(nèi)容放入SELECT語句的WHERE和ORDER BY子句中.如果在Open的lpszSQL參數(shù)中已包括了WHERE和ORDER BY子句,那么m_strFilter和m_strSort必需為空.

  調(diào)用無參數(shù)成員函數(shù)Close可以關(guān)閉記錄集.在調(diào)用了Close函數(shù)后,程序可以再次調(diào)用Open建立新的記錄集.CRecordset的析構(gòu)函數(shù)會調(diào)用Close函數(shù),所以當(dāng)刪除CRecordset對象時(shí)記錄集也隨之關(guān)閉。

10.5.5 滾動記錄

  CRecordset提供了幾個(gè)成員函數(shù)用來在記錄集中滾動,如下所示.當(dāng)用這些函數(shù)滾動到一個(gè)新記錄時(shí),框架會自動地把新記錄的內(nèi)容拷貝到域數(shù)據(jù)成員中.

void MoveNext( ); //前進(jìn)一個(gè)記錄

void MovePrev( ); //后退一個(gè)記錄

void MoveFirst( ); //滾動到記錄集中的第一個(gè)記錄

void MoveLast( ); //滾動到記錄集中的最后一個(gè)記錄

void SetAbsolutePosition( long nRows );
該函數(shù)用于滾動到由參數(shù)nRows指定的絕對位置處.若nRows為負(fù)數(shù),則從后往前滾動.例如,當(dāng)nRows為-1時(shí),函數(shù)就滾動到記錄集的末尾.注意,該函數(shù)不會跳過被刪除的記錄.

virtual void Move( long nRows, WORD wFetchType = SQL_FETCH_RELATIVE );
該函數(shù)功能強(qiáng)大.通過將wFetchType參數(shù)指定為SQL_FETCH_NEXT、SQL_FETCH_PRIOR、 SQL_FETCH_FIRST、SQL_FETCH_LAST和SQL_FETCH_ABSOLUTE,可以完成上面五個(gè)函數(shù)的功能.若 wFetchType為SQL_FETCH_RELATIVE,那么將相對當(dāng)前記錄移動,若nRows為正數(shù),則向前移動,若nRows為負(fù)數(shù),則向后移 動.

 

  如果在建立記錄集時(shí)選擇了CRecordset::skipDeletedRecords選項(xiàng),那么除了SetAbsolutePosition外,在滾動記錄時(shí)將跳過被刪除的記錄,這一點(diǎn)對象FoxPro這樣的數(shù)據(jù)庫十分重要.

  如果記錄集是空的,那么調(diào)用上述函數(shù)將產(chǎn)生異常.另外,必須保證滾動沒有超出記錄集的邊界.調(diào)用IsEOF和IsBOF可以進(jìn)行這方面的檢測.

 

BOOL IsEOF( ) const;
如果記錄集為空或滾動過了最后一個(gè)記錄,那么函數(shù)返回TRUE,否則返回FALSE.

BOOL IsBOF( ) const;
如果記錄集為空或滾動過了第一個(gè)記錄,那么函數(shù)返回TRUE,否則返回FALSE.

 

下面是一個(gè)使用IsEOF的例子:

while(!m_pSet->IsEOF( ))

m_pSet->MoveNext( );

調(diào)用GetRecordCound可獲得記錄集中的記錄總數(shù),該函數(shù)的聲明為

long GetRecordCount( ) const;
要注意這個(gè)函數(shù)返回的實(shí)際上是用戶在記錄集中滾動的最遠(yuǎn)距離.要想真正返回記錄總數(shù),只有調(diào)用MoveNext移動到記錄集的末尾(MoveLast不行).

 

10.5.6 修改、添加和刪除記錄

要修改當(dāng)前記錄,應(yīng)該按下列步驟進(jìn)行:

調(diào) 用Edit成員函數(shù).調(diào)用該函數(shù)后就進(jìn)入了編輯模式,程序可以修改域數(shù)據(jù)成員.注意不要在一個(gè)空的記錄集中調(diào)用Edit,否則會產(chǎn)生異常.Edit函數(shù)會 把當(dāng)前域數(shù)據(jù)成員的內(nèi)容保存在一個(gè)緩沖區(qū)中,這樣做有兩個(gè)目的,一是可以與域數(shù)據(jù)成員作比較以判斷哪些字段被改變了,二是在必要的時(shí)侯可以恢復(fù)域數(shù)據(jù)成員 原來的值.若再次調(diào)用Edit,則將從緩沖區(qū)中恢復(fù)域數(shù)據(jù)成員,調(diào)用后程序仍處于編輯模式.調(diào)用Move(AFX_MOVE_REFRESH)或 Move(0)可退出編輯模式(AFX_MOVE_REFRESH的值為0),同時(shí)該函數(shù)會從緩沖區(qū)中恢復(fù)域數(shù)據(jù)成員.

設(shè)置域數(shù)據(jù)成員的新值.

調(diào)用Update完成編輯.Update把變化后的記錄寫入數(shù)據(jù)源并結(jié)束編輯模式.

 

要向記錄集中添加新的記錄,應(yīng)該按下列步驟進(jìn)行:

調(diào) 用AddNew成員函數(shù).調(diào)用該函數(shù)后就進(jìn)入了添加模式,該函數(shù)把所有的域數(shù)據(jù)成員都設(shè)置成NULL(注意,在數(shù)據(jù)庫術(shù)語中,NULL是指沒有值,這與 C++的NULL是不同的).與Edit一樣,AddNew會把當(dāng)前域數(shù)據(jù)成員的內(nèi)容保存在一個(gè)緩沖區(qū)中,在必要的時(shí)侯,程序可以再次調(diào)用AddNew取 消添加操作并恢復(fù)域數(shù)據(jù)成員原來的值,調(diào)用后程序仍處于添加模式.調(diào)用Move(AFX_MOVE_REFRESH)可退出添加模式,同時(shí)該函數(shù)會從緩沖 區(qū)中恢復(fù)域數(shù)據(jù)成員.

設(shè)置域數(shù)據(jù)成員.

調(diào)用Update.Update把域數(shù)據(jù)成員中的內(nèi)容作為新記錄寫入數(shù)據(jù)源,從而結(jié)束了添加.

 

如果記錄集是快照,那么在添加一個(gè)新的記錄后,需要調(diào)用Requery重新查詢,因?yàn)榭煺諢o法反映添加操作.

要?jiǎng)h除記錄集的當(dāng)前記錄,應(yīng)按下面兩步進(jìn)行:

調(diào)用Delete成員函數(shù).該函數(shù)會同時(shí)給記錄集和數(shù)據(jù)源中當(dāng)前記錄加上刪除標(biāo)記.注意不要在一個(gè)空記錄集中調(diào)用Delete,否則會產(chǎn)生一個(gè)異常.

滾動到另一個(gè)記錄上以跳過刪除記錄.

 

上面提到的函數(shù)聲明為:

virtual void Edit( );throw( CDBException, CMemoryException );

virtual void AddNew( );throw( CDBException );

virtual void Delete( );throw( CDBException );

virtual BOOL Update( );throw( CDBException );
若更新失敗則函數(shù)返回FALSE,且會產(chǎn)生一個(gè)異常.

 

  在對記錄集進(jìn)行更改以前,程序也許要調(diào)用下列函數(shù)來判斷記錄集是否是可以更改的,因?yàn)槿绻诓荒芨牡挠涗浖羞M(jìn)行修改、添加或刪除將導(dǎo)致異常的產(chǎn)生.

BOOL CanUpdate( ) const; //返回TRUE表明記錄是可以修改、添加和刪除的.

BOOL CanAppend( ) const; //返回TRUE則表明可以添加記錄

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    亚洲男人天堂网在线视频| 精品国自产拍天天青青草原| 亚洲中文字幕在线综合视频| 好吊视频有精品永久免费| 国产美女精品午夜福利视频| 中文字幕人妻综合一区二区| 精品推荐国产麻豆剧传媒| 高跟丝袜av在线一区二区三区| 亚洲精品中文字幕熟女| 久久女同精品一区二区| 国产精品亚洲一级av第二区| 99国产一区在线播放| 欧美又黑又粗大又硬又爽| 欧美精品在线播放一区二区| 日韩成人中文字幕在线一区| 一区二区日韩欧美精品| 欧美不雅视频午夜福利| 久久三级国外久久久三级| 欧美精品二区中文乱码字幕高清| 富婆又大又白又丰满又紧又硬| 九九热视频经典在线观看| 国产传媒一区二区三区| 五月婷婷综合激情啪啪| 午夜精品成年人免费视频| 办公室丝袜高跟秘书国产| 中国一区二区三区人妻| 91久久精品中文内射| 国产在线不卡中文字幕| 美女激情免费在线观看| 国产香蕉国产精品偷在线观看| 午夜亚洲精品理论片在线观看| 初尝人妻少妇中文字幕在线| 日本熟妇熟女久久综合| 日韩高清毛片免费观看| 中文精品人妻一区二区| 日韩精品一区二区三区射精| 国产一区国产二区在线视频| 一区二区欧美另类稀缺| 婷婷激情四射在线观看视频| 国产不卡免费高清视频| 91日韩欧美国产视频|