访问ODBC数据库 目标 在应用程序中访问O D B C兼容的数据库。 策略 利用M F C的C D a t a b a s e和C R e c o r d S e t类访问O D B C数据库。C D a t a b a s e类用来打开数据库, C R e c o r d S e t类用来打开数据库中的表并读取其中的记录。 步骤 1. 设置应用程序 首先,要保证以下的包含文件在S t d a f x . h文件中。若在创建应用程序时,为数据库支持选 择了Header files Only, 则A p p Wi z a r d把这些包含文件添加到工程中。 #ifndef _AFX_NO_DB_SUPPORT #include <afxdb.h> // MFC ODBC database classes # e n d i f // _AFX_NO_DB_SUPPORT #ifndef _AFX_NO_DAO_SUPPORT #include <afxdao.h> // MFC DAO database classes #endif // _AFX_NO_DAO_SUPPORT 2. 使用O D B C数据库 1) 可以在任何地方创建一个数据库类的实例。但习惯上,这个实例应放在文档类中。 CDocument m_WzdDocument; 2) 然后,使用Open( )成员函数打开数据库,从用户响应N e w或者Open File命令。这些命 令可以在文档类中进行处理。 i f ( ! m _ W z d D a t a b a s e . O p e n ( N U L L , // Data source name, // NULL if defined in // DSN below FA L S E , // exclusive access, // NOT SUPPORT E D , // should always be FA L S E FALSE, // TRUE = read only access "ODBC;DSN=MS Access 97 Database") // connect string where DSN= is the data source name // found in ODBC32 utility, UID= is user id, PSW= is password ) { AfxMessageBox("Failed to open database."); } 这里用的连接字符串基于O D B C 3 2设置应用程序中的数据库条目的名称。可以在系统的 控制面板中找到O D B C 3 2设置应用程序。使用O D B C 3 2,可以增加和删除其他数据库。甚至可 以使用O D B C去访问一个D A O数据库。 3) 一般也习惯于在文档类中创建一个捆绑函数以返回指向数据库的一个指针。 // Attributes p u b l i c : CDatabase *GetDatabase(){return &m_WzdDatabase;}; 4) 可以在文档类的DeleteContents( )中关闭数据库。 // close database m _ W z d D a t a b a s e . C l o s e ( ) ; 3. 打开一个O D B C记录集 1) 使用C l a s s Wi z a r d创建一个派生于C R e c o r d S e t的一个新的记录集类。选择C R e c o r d S e t将 会使C l a s s Wi z a r d进入一个以前未见到的状态,它使C l a s s Wi z a r d进入Record Set Wi z a r d。首先 提示选择想要创建的记录类的类型: O D B C或D A O。默认选项是O D B C。然后,从当前O D B C 数据库列表中选择一个记录集要访问的数据库。C l a s s Wi z a r d试图打开所选中的数据库。若成 功,则提示选择哪个(些)表被包含在记录集中。选择多表将允许同时在多个表上进行操作,如 进行连接时。最后, C l a s s Wi z a r d创建派生的记录集类。注意在此类中所选择表的每一字段都 对应一个成员变量。当记录集打开后,在其中游览时,可以通过这些成员变量获得字段值。 2) 用如下方式打开数据库记录集类。 CWzdRecordSet wzdSet(GetDocument()->GetDatabase()); w z d S e t . O p e n ( ) ; 4. 使用O D B C记录集 1) 使用以下方式,滚动记录集中的记录。 while (! wzdSet.IsEOF()) { // column values can be accessed from record // set member variables like these: // wzdSet.m_CustomerID // wzdSet.m_CompanyName // wzdSet.m_ContactName // etc. w z d S e t . M o v e N e x t ( ) ; } 2) 使用以下方式,返回第一个记录。 wzdSet.MoveFirst( ); 3) 使用以下方式,判断记录集是否可以被更新或添加。 // if we can’t update or append records, leave now if (!wzdSet.CanUpdate() || !wzdSet.CanAppend()) r e t u r n ; 4) 使用以下方式,在记录集中添加一个记录。 t r y { // add new record w z d S e t . A d d N e w ( ) ; // initialize each field w z d S e t . m _ C u s t o m e r I D = " A B C D E " ; wzdSet.m_CompanyName="ABC Inc."; / / e t c . // update database w z d S e t . U p d a t e ( ) ; } catch (CDBException *e) { // AddNew failed A f x M e s s a g e B o x ( e - > m _ s t r E r r o r ) ; e - > D e l e t e ( ) ; } 注意,一个记录只有在调用了CRecordSet::Update( )后才实际上被添加。 5) 使用以下方式,编辑数据库中的一个记录。 t r y { w z d S e t . E d i t ( ) ; // update affected fields wzdSet.m_CompanyName="ABCEF Inc."; w z d S e t . m _ C o n t a c t N a m e = " F r a n k " ; / / e t c . // update database w z d S e t . U p d a t e ( ) ; } catch (CDBException *e) { // Edit failed A f x M e s s a g e B o x ( e - > m _ s t r E r r o r ) ; e - > D e l e t e ( ) ; } 6) 使用以下方式,从数据库中删除一个记录。 t r y { // delete record to which we’re currently opened w z d S e t . D e l e t e ( ) ; } catch (CDBException *e) { // Delete failed A f x M e s s a g e B o x ( e - > m _ s t r E r r o r ) ; e - > D e l e t e ( ) ; } 7) 使用以下方式关闭记录集。 wzdSet.Close( ); 5. 用W H E R E打开一个O D B C记录集 可以使用以下方式,用简单的WHERE SQL过滤器打开记录集,该过滤器过滤掉所有不匹 配的记录。在本例中,只有在[ C o u n t r y ]字段上取值为U K的记录才可被访问。 wzdSet.m_strFilter = "[Country]='UK'"; if(!wzdSet.Open() || wzdSet.IsEOF()) { AfxMessageBox("Cannot find records."); } // scroll through records as above... while (! wzdSet.IsEOF()) { w z d S e t . M o v e N e x t ( ) ; } w z d S e t . C l o s e ( ) ; 6. 用S E L E C T打开一个O D B C记录集 可以使用如下代码用完全的SQL SELECT语句打开记录集。该语句允许被指定为j o i n、 s o r t等。请注意,m _ s t r F i l t e r中的内容会被自动加到S Q L命令后面。 wzdSet.m_strFilter = ""; // appended to the following! if (!wzdSet.Open(AFX_DB_USE_DEFA U LT _ T Y P E , //>>>>>>>>>> SELECT STA RT S "SELECT [CustomerID], [CompanyName], [ContactName], \ [ C o n t a c t Title], [Address], [City], [Region], [PostalCode], \ [Country], [Phone], [Fax] \FROM [Customers] \ WHERE [Country] = 'Mexico'") || //<<<<<<<<<<<< SELECT ENDS w z d S e t . I s E O F ( ) ) {AfxMessageBox("Cannot find records."); } // scroll through records as above... while (! wzdSet.IsEOF()) { w z d S e t . M o v e N e x t ( ) ; } w z d S e t . C l o s e ( ) ; 7. 创建O D B C事务 一些数据库操作可能要求一次访问几个数据库表。这时,一个表变化要求别的表也作相 应改变。在这种情况下,若在改变一个表时发生了错误,用户必须取消这种变化,还要相应 地取消在其他表中所作的改变。用数据库术语,称为事务恢复。C D a t a b a s e的B e g i n Trans( )、 C o m m i t Trans( )和R o l l b a c k Trans( )成员函数支持事务恢复。 // Create a transaction we can rollback G e t D o c u m e n t ( ) - > G e t D a t a b a s e ( ) - > B e g i n Tr a n s ( ) ; t r y { // perform transactions on several database tables/records w z d S e t . O p e n ( ) ; w z d S e t . U p d a t e ( ) ; : : : // No exception occurred so we can commit // the previous transactions G e t D o c u m e n t ( ) - > G e t D a t a b a s e ( ) - > C o m m i t Tr a n s ( ) ; } catch (CDBException *e) { // An exception occurred, rollback the transaction G e t D o c u m e n t ( ) - > G e t D a t a b a s e ( ) - > R o l l b a c k ( ) ; A f x M e s s a g e B o x ( e - > m _ s t r E r r o r ) ; e - > D e l e t e ( ) ; } 说明 ■ 用户也可用CDatabase::OpenEx( )打开一个数据库。然而,这样做,用户必须保证省略 掉O D B C,否则,部分或全部连接字符串的打开将失败。若数据库要求有用户I D和口 令,则可以在连接字符串中指定这些值。若省略掉,则系统在运行时要求用户输入这 些值,如果找不到指定的数据库,它也会提示用户。然而,若使用OpenEx( )函数,也 可以设置选项以决定是要显示还是不显示这种提示要求。若只是想简单地在不告知用 户前提下,判断数据库是否存在的话,则后一种选项是有用的。 ■ 当使用CDatabase::OpenEx( )时,系统只通过数据库异常(database exceptions)来报错。 因此必须使用t r y / c a t c h语句来捕获任何错误。 ■ O D B C驱动程序允许应用程序访问任何第三方供应商的数据库管理系统( D B M S )。然而, 这种灵活性带来一个性能隐患。因为O D B C在处理之前,用户数据库请求首先编码为 一个S Q L文本命令,驱动程序必须把它转换成一种内部命令。若移植性对应用程序来说非常重要,则可能别无选择。若在最近一段时间,使用的是同一供应商的产品,那 么在可能的情况下,应直接使用供应商所提供的数据库A P I,是以牺牲移植性换取速 度。D A O的效率要比O D B C高些,只是因为它不是使用S Q L与管理系统交流,而是直 接封装进微软Jet Engine数据库管理系统的A P I。 CD说明 在C D上执行该工程时,首先在W z d Vi e w. c p p中的O n TestWzd( )上设置断点。然后单击 Te s t / W z d菜单项,一步步地观察O D B C数据库的访问。
目标
在应用程序中访问O D B C兼容的数据库。
策略
利用M F C的C D a t a b a s e和C R e c o r d S e t类访问O D B C数据库。C D a t a b a s e类用来打开数据库,
C R e c o r d S e t类用来打开数据库中的表并读取其中的记录。
步骤
1. 设置应用程序
首先,要保证以下的包含文件在S t d a f x . h文件中。若在创建应用程序时,为数据库支持选
择了Header files Only, 则A p p Wi z a r d把这些包含文件添加到工程中。
#ifndef _AFX_NO_DB_SUPPORT
#include <afxdb.h> // MFC ODBC database classes
# e n d i f // _AFX_NO_DB_SUPPORT
#ifndef _AFX_NO_DAO_SUPPORT
#include <afxdao.h> // MFC DAO database classes
#endif // _AFX_NO_DAO_SUPPORT
2. 使用O D B C数据库
1) 可以在任何地方创建一个数据库类的实例。但习惯上,这个实例应放在文档类中。
CDocument m_WzdDocument;
2) 然后,使用Open( )成员函数打开数据库,从用户响应N e w或者Open File命令。这些命
令可以在文档类中进行处理。
i f ( ! m _ W z d D a t a b a s e . O p e n (
N U L L , // Data source name,
// NULL if defined in
// DSN below
FA L S E , // exclusive access,
// NOT SUPPORT E D ,
// should always be FA L S E
FALSE, // TRUE = read only access
"ODBC;DSN=MS Access 97 Database")
// connect string where DSN= is the data source name
// found in ODBC32 utility, UID= is user id, PSW= is password
) {
AfxMessageBox("Failed to open database.");
}
这里用的连接字符串基于O D B C 3 2设置应用程序中的数据库条目的名称。可以在系统的
控制面板中找到O D B C 3 2设置应用程序。使用O D B C 3 2,可以增加和删除其他数据库。甚至可
以使用O D B C去访问一个D A O数据库。
3) 一般也习惯于在文档类中创建一个捆绑函数以返回指向数据库的一个指针。
// Attributes
p u b l i c :
CDatabase *GetDatabase(){return &m_WzdDatabase;};
4) 可以在文档类的DeleteContents( )中关闭数据库。
// close database
m _ W z d D a t a b a s e . C l o s e ( ) ;
3. 打开一个O D B C记录集
1) 使用C l a s s Wi z a r d创建一个派生于C R e c o r d S e t的一个新的记录集类。选择C R e c o r d S e t将
会使C l a s s Wi z a r d进入一个以前未见到的状态,它使C l a s s Wi z a r d进入Record Set Wi z a r d。首先
提示选择想要创建的记录类的类型: O D B C或D A O。默认选项是O D B C。然后,从当前O D B C
数据库列表中选择一个记录集要访问的数据库。C l a s s Wi z a r d试图打开所选中的数据库。若成
功,则提示选择哪个(些)表被包含在记录集中。选择多表将允许同时在多个表上进行操作,如
进行连接时。最后, C l a s s Wi z a r d创建派生的记录集类。注意在此类中所选择表的每一字段都
对应一个成员变量。当记录集打开后,在其中游览时,可以通过这些成员变量获得字段值。
2) 用如下方式打开数据库记录集类。
CWzdRecordSet wzdSet(GetDocument()->GetDatabase());
w z d S e t . O p e n ( ) ;
4. 使用O D B C记录集
1) 使用以下方式,滚动记录集中的记录。
while (! wzdSet.IsEOF())
{
// column values can be accessed from record
// set member variables like these:
// wzdSet.m_CustomerID
// wzdSet.m_CompanyName
// wzdSet.m_ContactName
// etc.
w z d S e t . M o v e N e x t ( ) ;
}
2) 使用以下方式,返回第一个记录。
wzdSet.MoveFirst( );
3) 使用以下方式,判断记录集是否可以被更新或添加。
// if we can’t update or append records, leave now
if (!wzdSet.CanUpdate() || !wzdSet.CanAppend())
r e t u r n ;
4) 使用以下方式,在记录集中添加一个记录。
t r y
{
// add new record
w z d S e t . A d d N e w ( ) ;
// initialize each field
w z d S e t . m _ C u s t o m e r I D = " A B C D E " ;
wzdSet.m_CompanyName="ABC Inc.";
/ / e t c .
// update database
w z d S e t . U p d a t e ( ) ;
}
catch (CDBException *e)
{
// AddNew failed
A f x M e s s a g e B o x ( e - > m _ s t r E r r o r ) ;
e - > D e l e t e ( ) ;
}
注意,一个记录只有在调用了CRecordSet::Update( )后才实际上被添加。
5) 使用以下方式,编辑数据库中的一个记录。
t r y
{
w z d S e t . E d i t ( ) ;
// update affected fields
wzdSet.m_CompanyName="ABCEF Inc.";
w z d S e t . m _ C o n t a c t N a m e = " F r a n k " ;
/ / e t c .
// update database
w z d S e t . U p d a t e ( ) ;
}
catch (CDBException *e)
{
// Edit failed
A f x M e s s a g e B o x ( e - > m _ s t r E r r o r ) ;
e - > D e l e t e ( ) ;
}
6) 使用以下方式,从数据库中删除一个记录。
t r y
{
// delete record to which we’re currently opened
w z d S e t . D e l e t e ( ) ;
}
catch (CDBException *e)
{
// Delete failed
A f x M e s s a g e B o x ( e - > m _ s t r E r r o r ) ;
e - > D e l e t e ( ) ;
}
7) 使用以下方式关闭记录集。
wzdSet.Close( );
5. 用W H E R E打开一个O D B C记录集
可以使用以下方式,用简单的WHERE SQL过滤器打开记录集,该过滤器过滤掉所有不匹
配的记录。在本例中,只有在[ C o u n t r y ]字段上取值为U K的记录才可被访问。
wzdSet.m_strFilter = "[Country]='UK'";
if(!wzdSet.Open() || wzdSet.IsEOF())
{
AfxMessageBox("Cannot find records.");
}
// scroll through records as above...
while (! wzdSet.IsEOF())
{
w z d S e t . M o v e N e x t ( ) ;
}
w z d S e t . C l o s e ( ) ;
6. 用S E L E C T打开一个O D B C记录集
可以使用如下代码用完全的SQL SELECT语句打开记录集。该语句允许被指定为j o i n、
s o r t等。请注意,m _ s t r F i l t e r中的内容会被自动加到S Q L命令后面。
wzdSet.m_strFilter = ""; // appended to the following!
if (!wzdSet.Open(AFX_DB_USE_DEFA U LT _ T Y P E ,
//>>>>>>>>>> SELECT STA RT S
"SELECT [CustomerID], [CompanyName], [ContactName], \
[ C o n t a c t Title], [Address], [City], [Region], [PostalCode], \
[Country], [Phone], [Fax] \FROM [Customers] \
WHERE [Country] = 'Mexico'") ||
//<<<<<<<<<<<< SELECT ENDS
w z d S e t . I s E O F ( ) )
{AfxMessageBox("Cannot find records.");
}
// scroll through records as above...
while (! wzdSet.IsEOF())
{
w z d S e t . M o v e N e x t ( ) ;
}
w z d S e t . C l o s e ( ) ;
7. 创建O D B C事务
一些数据库操作可能要求一次访问几个数据库表。这时,一个表变化要求别的表也作相
应改变。在这种情况下,若在改变一个表时发生了错误,用户必须取消这种变化,还要相应
地取消在其他表中所作的改变。用数据库术语,称为事务恢复。C D a t a b a s e的B e g i n Trans( )、
C o m m i t Trans( )和R o l l b a c k Trans( )成员函数支持事务恢复。
// Create a transaction we can rollback
G e t D o c u m e n t ( ) - > G e t D a t a b a s e ( ) - > B e g i n Tr a n s ( ) ;
t r y
{
// perform transactions on several database tables/records
w z d S e t . O p e n ( ) ;
w z d S e t . U p d a t e ( ) ;
: : :
// No exception occurred so we can commit
// the previous transactions
G e t D o c u m e n t ( ) - > G e t D a t a b a s e ( ) - > C o m m i t Tr a n s ( ) ;
}
catch (CDBException *e)
{
// An exception occurred, rollback the transaction
G e t D o c u m e n t ( ) - > G e t D a t a b a s e ( ) - > R o l l b a c k ( ) ;
A f x M e s s a g e B o x ( e - > m _ s t r E r r o r ) ;
e - > D e l e t e ( ) ;
}
说明
■ 用户也可用CDatabase::OpenEx( )打开一个数据库。然而,这样做,用户必须保证省略
掉O D B C,否则,部分或全部连接字符串的打开将失败。若数据库要求有用户I D和口
令,则可以在连接字符串中指定这些值。若省略掉,则系统在运行时要求用户输入这
些值,如果找不到指定的数据库,它也会提示用户。然而,若使用OpenEx( )函数,也
可以设置选项以决定是要显示还是不显示这种提示要求。若只是想简单地在不告知用
户前提下,判断数据库是否存在的话,则后一种选项是有用的。
■ 当使用CDatabase::OpenEx( )时,系统只通过数据库异常(database exceptions)来报错。
因此必须使用t r y / c a t c h语句来捕获任何错误。
■ O D B C驱动程序允许应用程序访问任何第三方供应商的数据库管理系统( D B M S )。然而,
这种灵活性带来一个性能隐患。因为O D B C在处理之前,用户数据库请求首先编码为
一个S Q L文本命令,驱动程序必须把它转换成一种内部命令。若移植性对应用程序来说非常重要,则可能别无选择。若在最近一段时间,使用的是同一供应商的产品,那
么在可能的情况下,应直接使用供应商所提供的数据库A P I,是以牺牲移植性换取速
度。D A O的效率要比O D B C高些,只是因为它不是使用S Q L与管理系统交流,而是直
接封装进微软Jet Engine数据库管理系统的A P I。
CD说明
在C D上执行该工程时,首先在W z d Vi e w. c p p中的O n TestWzd( )上设置断点。然后单击
Te s t / W z d菜单项,一步步地观察O D B C数据库的访问。