MFC ODBC 编程

来源:百度文库 编辑:神马文学网 时间:2024/04/29 22:53:29

MFC ODBC 编程

1  了解 MFC ODBC

MFC 对 ODBC 的封装主要是开发了CDatabase 类和 CRecordSet 类。

CDatabase类主要是为了建立应用程序和数据源的连接功能。

CRecordSet类主要是对数据集的操作。

记录的查询:主要使用CRecordSet类的Open()方法和Requery()成员函数。在使用CRecordSet的类对象之前,必须使用CRecordSet的成员函数Open()来获得有效的记录集。一旦使用过Open()函数,再次查询时使用Requery()函数就可以了。

记录的添加:只用AddNew()函数,不过必须保证在数据库是在允许添加的模式打开的。

记录的删除:调用Delete()函数完成,在使用完Delete()函数之后不用调用Update()函数了。

记录的修改:调用Edit()函数完成,在使用过Edit()函数之后需要调用Update()函数将修改结果存入数据库。

撤销数据库更新操作:如果在增加、删除或者编辑记录之后,想撤销原来的操作,应该在Update()函数之前使用Move()函数。CRecordSet::Move(AFX_MOVE_REFRESH); 该函数用于撤消增加或修改模式,并恢复在增加或修改模式之前的当前记录。其中参 AFX_MOVE_REFRESH的值为零。

直接执行SQL操作:这个需要调用CDatabase类的ExecuteSQL()函数。需要注意的是,由于不同DBMS提供的数据操作语句不尽相同,直接执行SQL语句可能会破坏软件的DBMS无关性,因此在应用中应当慎用此类操作。

MFC ODBC的数据库操作过程:

首先,应用程序应该先使用CDatabase类的Open()函数实现与ODBC数据源的连接,然后传递CDatabase类的指针到CRecordSet类的构造函数中,使CRecordSet对象与原来的数据源结合起来。完成了数据源的连接之后,大量的操作集中在数据集之上。完成操作之后,先关闭所有记录集的连接,然后关闭数据源的连接。

1.1  CDatabase

CDatabase 类用于应用程序建立同数据源的连接。CDatabase 类包含一个 m_hdbc 变量,它代表了数据源的连接句柄。如果要建立 CDatabase 类的实例,应先调用该类的构造函数,再调用 Open 函数,通过调用,初始化环境变量,并执行与数据源的连接。关闭数据源连接的函数是Close。

CDatabase 类提供了对数据库进行操作的函数,为了执行事务操作,CDatabase 类提供了 BeginTrans函数,当全部数据都处理完成后,可以通过调用CommitTrans函数提交事务, 或者在特殊情况下通过调用Rollback函数将处理回退。

CDatabase 类提供的函数可以用于返回数据源的特定信息, 例如通过GetConnect函数返回在使用函数Open连接数据源时的连接字符串,通过调用IsOpen 函数返回当前的CDatabase 实例是否已经连接到数据源上,通过调用 CanUpdate 函数返回当前的CDatabase 实例是否是可更新的, 通过调用CanTransact函数返回当前的 CDatabase 实例是否支持事务操作,等等。

总之,CDatabase 类为 C++数据库开发人员提供了ODBC 的面向对象的编程接口。

1.2  CRecordSet

CRecordSet 类实现对结果集的数据操作。CRecordSet 类定义了从数据库接收或者发送数据到数据库的成员变量,CRecordSet 类定义的记录集可以是表的所有列,也可以是其中的一列,这是由 SQL语句决定的。

CRecordSet 类的成员变量m_hstmt 代表了定义该记录集的SQL 语句句柄,m_nFields成员变量保存了记录集中字段的个数,m_nParams 成员变量保存了记录集所使用的参数个数。

CRecordSet 的记录集通过CDatabase 实例的指针实现同数据源的连接,即CRecordSet 的成员变量m_pDatabase。

如果记录集使用了WHERE 子句,m_strFilter 成员变量将保存记录集的WHERE 子句的内容, 如果记录集使用了 ORDER BY 子句,m_strSort 成员变量将保存记录集的ORDER BY 子句的内容。

由多种方法可以打开记录集, 最常用的方法是使用Open 函数执行一个SQL SELECT 语句。 有如下四种类型的记录集:

•  CRecordset::dynaset:

动态记录集, 支持双向游标, 并保持同所连接的数据源同步, 对数据的更新操作可以通过一个fetch操作获取。

•  CRecordset::snapshot:

静态快照,一旦形成记录集,此后数据源的所有改变都不能体现在记录集里,应用程序必须重新进行查询,才能获取对数据的更新。该类型记录集也支持双向游标。

•  CRecordset::dynamic:

同 CRecordset::dynaset记录集相比,CRecordset::dynamic记录还能在 fetch 操作里同步其它用户对数据的重新排序。

•  CRecordset::forwardOnly:

除了不支持逆向游标外,其它特征同CRecordset::snapshot相同。

6.2  MFC ODBC 数据库访问技术

2.1  记录查询

使用 CRecordSet 的 Open()和 Requery()成员函数可以实现记录查询。需要注意的是,在使用CRecordSet 的类对象之前, 必须使用CRecordSet 的成员函数Open()来获得有效的记录集。 一旦使用过Open()函数, 再次查询时使用 Requery()函数就可以了。 在调用Open()函数时, 如果已经将一个打开的CDatabase 对象指针传递给 CRecordSet类对象的m_pDatabase成员变量, 那么,      CRecordSet类对象将使用该数据库对象建立ODBC连接;否则,如果m_pDatabase为空指针,对象就需要就新建一个CDatabase 类对象并使其与缺省的数据源相连,然后进行CRecordSet 类对象的初始化。缺省数据源由GetDefaultConnect()函数获得。也可以通过特定的 SQL 语句为 CRecordSet 类对象指定数据源,并以它来调用CRecordSet 类的 Open()函数,例如:

myRS.Open(AFX_DATABASE_USE_DEFAULT,strSQL);

如果没有指定参数, 程序则使用缺省的SQL 语句, 即对在GetDefaultSQL()函数中指定的SQL 语句进行操作,代码如下:

CString CMyRS::GetDefaultSQL()

{return_T("[Name],[Age]");}

对于 GetDefaultSQL()函数返回的表名,对应的缺省操作是SELECT 语句,例如:

SELECT * FROM BasicData,MainSize

在查询过程中,也可以利用CRecordSet 类的成员变量m_strFilter 和 m_strSort 来执行条件查询和结果排序。m_strFilter 用于指定过滤字符串,存放着SQL 语句中关键字WHERE 后的条件语句;m_strSort 用于指定用于排序的字符串,存放着SQL 语句中关键字ORDER BY 后的字符串。例如:

myRS.m_strFilter="Name='刘鹏'";

myRS.m_strSort="Age";

myRS.Requery();

数据库查询中对应的SQL 语句为:

SELECT * FROM BasicData WHERE Name='刘鹏' ORDER BY Age

除了直接赋值给成员变量m_strFilter 以外, 还可以通过参数化实现条件查询。 利用参化可以更直观、更方便地完成条件查询任务。参数化方法的步骤如下:

(1) 声明参变量,代码如下:

CString strName;

int nAge;

(2) 在构造函数中初始化参变量如下:

strName =_T("");

nAge =0;

m_nParams=2;

(3) 将参变量与对应列绑定,代码如下:

pFX->SetFieldType(CFieldExchange::param)

RFX_Text(pFX,_T("Name"), strName);

RFX_Single(pFX,_T("Age"), nAge);

完成以上步骤之后就可以利用参变量进行条件查询了,代码如下:

m_pmyRS->m_strFilter="Name=? AND age=?";

m_ pmyRS -> strName ="刘鹏";

m_ pmyRS ->nAge=26;

m_ pmyRS ->Requery();

参变量的值按绑定的顺序替换查询字串中的“?”通配符。

如果查询的结果是多条记录,可以利用CRecordSet 类的成员函数Move(),MoveNext(),MovePrev(),MoveFirst()和MoveLast()来移动记录光标。

2.2  记录添加

使用 AddNew()成员函数能够实现记录添加,需要注意的是,在记录添加之前必须保证数据库是以允许添加的方式打开的,需要调用Update()更新,代码如下:

m_ pmyRS ->AddNew();      // 在表的末尾添加新记录

m_ pmyRS ->SetFieldNull(&(m_pSet->m_type),FALSE);

m_pmyRS->m_strName=”刘鹏”;     //输入新的字段值

m_ pmyRS ->m_nAge=26; // 输入新的字段值

m_ pmyRS ->Update();  // 将新记录存入数据库

m_ pmyRS ->Requery(); // 重新建立记录集

2.3  记录删除

调用 Delete()成员函数能够实现记录删除,在调用Delete()函数后不需调用Update()函数,代码如下:

m_pmyRS ->Delete();

if(!m_ pmyRS ->IsEOF())

m_ pmyRS ->MoveNext();

else

m_ pmyRS ->MoveLast();

 

2.4  记录修改

调用 Edit()成员函数可以实现记录修改, 在修改完成后需要调用Update()将修改结果存入数据库, 代码如下:

m_ pmyRS ->Edit();

m_ pmyRS ->m_strName="刘波"; // 修改当前记录字段值

...

m_ pmyRS ->Update();

m_pmyRS->Requerey();

2.5  撤销数据库更新操作

如果用户增加或者修改记录后希望放弃当前操作,可以在调用Update()函数之前调 用 Move()函数,就可以使数据库更新撤销了,代码如下:

CRecordSet::Move(AFX_MOVE_REFRESH);

该函数用于撤消增加或修改模式,并恢复在增加或修改模式之前的当前记录。其中AFX_MOVE_REFRESH的值为零。

2.6  直接执行 SQL 语句

虽然通过 CRecordSet 类我们可以完成大多数的数据库查询操作,而且在CRecordSet 类的 Open()成员函数中也可以提供SQL 语句,但有的时候我们还想进行一些其他操作,例如建立新表、删除表、建立新的字段等等,这时就需要用到CDatabase 类的直接执行SQL 语句的机制。 通过调用CDatabase 类的 ExecuteSQL()成员函数就能够完成SQL 语句的直接执行,代码如下:

BOOL CMyDB::ExecuteSQLWithReport (const CString& strSQL)

{

TRY

{

m_pMyDB->ExecuteSQL(strSQL);   // 直接执行 SQL 语句

}

CATCH(CDBException,e)

{

CString strMsg;

strMsg.LoadString(IDS_EXECUTE_SQL_FAILED);

strMsg+=strSQL;

return FALSE;

}

END_CATCH

return TRUE;

}

需要注意的是,由于不同DBMS 提供的数据操作语句不尽相同,直接执行SQL 语句可能会破坏软件的DBMS 无关性,因此在应用中应当慎用此类操作。

2.7  MFC ODBC 的数据库操作过程

ODBC API编程类似,MFC的ODBC编程也要先建立同ODBC 数据源的连接,这个过程由一个CDatabase对象的Open函数实现。然后CDatabase对象的指针将被传递到CRecordSet对象的构造函数里,使CRecordSet 对象与当前建立起来的数据源连接结合起来。

完成数据源连接之后, 大量的数据库编程操作将集中在记录集的CRecordSet 类操作上。在应用程序退出运行状态的时候, 需要将所有的记录集关闭,并关闭所有同数据源的连接。

3  本 章 小 结

本章介绍了 MFC ODBC 编程方法和过程。与ODBC API 编程相比,MFC 编程更适用于界面型数据库应用程序的开发,由于MFC 的广泛支持,ODBC 编程可以对数据进行很好地表示。

然而MFC 的 CDatabase 类和 CRecordset类提供的数据库操作函数非常有限,支持的游标类型也很有限,限制了高效的数据库开发。

从编程层次上,ODBC 的 MFC 编程则属于高级编程。   参考《VC++数据库编程》