ODBC中如何使用CRecordset类操作数据库

分类:编程技术 时间:2024-02-20 15:28 浏览:0 评论:0
0
如何在ODBC中使用CRecordset类来操作数据库。针对这一问题,本文详细介绍了相应的分析和解答。希望能够帮助更多想要解决这个问题的朋友找到更简单、更容易的方法。

1. MFC中的ODBC类

主要有CDatabase、CRecordset、CRecordview、CDBException、CFieldExchange。这些类封装了ODBC SDK功能,可以方便地操作支持ODBC的数据库。
(1)CDatabase类:封装了应用程序与需要访问的数据库之间的连接,控制事务的提交和执行SQL语句的方法。

(2)CRecordset类:封装了操作数据库的大部分方法,包括浏览、修改记录、控制光标移动、排序等操作。 CRecordset类是MFC的ODBC类中最重要、最强大的类sses。 CRecordset 类对象提供从数据源提取的一组记录。在多任务操作系统或网络环境中,多个用户可以共享同一个数据源。共享数据的一个主要问题是如何协调不同用户对数据源的修改。 CRecordset提供了几种不同的方法来处理这个问题,这将取决于程序使用哪种类型的记录集。

CRecordset对象通常有两种形式使用:动态行集(dynasets)和快照(snapshots)。动态行集可以与其他用户所做的更改同步,而快照集是数据的静态视图。当其他用户更改记录(包括修改、添加和删除)时,快照中的记录不受影响。也就是说,快照不反映其他用户对数据源记录所做的更改。快照不会反映更改,直到调用 CRecordset::Requery 重新查询。每个表格均打开记录集时提供一组记录。不同之处在于,当滚动到动态行集中的记录时,对该记录所做的更改是由应用程序中的其他用户或其他记录集进行的。将相应地显示更改。例如,在火车网络销售系统中,共享数据的变化应该实时显示。

(3)CRecordView类:提供与CRecordset对象连接的视图,可以在视图中的控件与数据库数据之间建立对应关系。它还支持游标和记录修改等操作。

(4)CDBException类:提供数据库操作的异常处理。

(5)CFieldExchange类:提供用户变量与数据库字段的数据交换。

2.域数据成员和数据交换

CRecordset类代表一个记录集。用户一般使用ClassWizard创建CRecordset的派生类。 ClassWizard可以创建一批派生记录集类的数据成员。这些数据成员对应于记录的每个字段,称为字段数据成员或域数据成员。域数据成员与表中的字段具有相似的名称,并且它们的类型匹配。
例如:这是 CRecordset 类的派生类的定义
class CSetdata: public CRecordset
{
public:
CSetdata(CDatabase* pDatabase = NULL );< br/> DECLARE_DYNAMIC(CSetdata)

//字段/参数数据
//{{AFX_FIELD(CSetdata, CRecordset)
//定义字段数据成员变量,使用对于字段数据成员来说,要与记录集的相应字段交换数据,它充当缓冲区或中间桥梁。也就是说,我们在处理记录集的时候,实际上是对域数据成员进行操作,而不是直接对数据库中的数据进行操作。
CString m_number; >// 重写
// ClassWizard 生成的虚函数重写
//{{AFX_VIRTUAL(CSetdata))
public:
virtual CString GetDefaultConnect(); // 默认连接字符串
virtual CString GetDefaultSQL(); // 记录集的默认 SQL
virtual void DoFieldExchange(CFieldExchange* pFX); // RFX 支持
//}}AFX_VIRTUAL

// 实现
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
};

#endif

字段数据成员用于保存记录的各个字段。它们是程序和记录之间的缓冲区。字段数据成员代表当前记录。当滚动到记录集中的一条记录时,框架会自动将记录的每个字段复制到记录集对象的字段数据成员中。当用户想要修改当前记录或者添加新记录时,程序首先将各个字段的新值放入域数据成员中,然后调用相应的CRecordset成员函数将域数据成员设置到域数据成员中。数据源。

不难看出记录集和数据源之间存在数据交换问题。 CRecordset 类使用记录字段交换 (RFX) 机制在字段数据成员和数据源之间自动交换数据。 RFX 机制类似于对话数据交换 (DDX)。 CRecordset的成员函数DoFieldExchange负责数据交换任务,在该函数中调用了一系列的RFX函数。当用户使用ClassWizard加入域数据成员时,ClassWizard将自动在DoFieldExchange中创建RFX。
典型的DoFieldExchange函数

void CSetdata::DoFieldExchange(CFieldExchange* pFX)
{
//{{AFX_FIELD_MAP(CSetdata)
pFX->SetFieldType ( CFieldExchange::outputColumn);
RFX_Text(pFX, _T("[number]"), m_number); //实现域数据成员与数据源之间的数据交换
RFX_Text(pFX, _T ("[name]"), m_name);
RFX_Text(pFX, _T("[sex]"), m_sex );
RFX_Long(pFX, _T("[age]"), m_age) ;
//}}AFX_FIELD_MAP
pFX->SetFieldType(CFieldExchange::param);
RFX_Text(pFX,_T ("[]"),数字);
}

3.记录集的创建和关闭

要使用MFC的ODBC类来操作数据库,首先要创建CRecordset的派生类来关联相应的数据表。然后调用Open()函数查询数据源中的数据并创建记录集。另外,在Open函数中,还可能调用GetDefaultConnect和GetDefaultSQL函数。
(1)首先,派生类的构造函数中会有一个参数指向一个CDatabase对象来获取数据源。函数如下:
CRecordset(CDatabase* pDatabase = NULL);
如果pDatabase为NULL,则Open函数中会自动构造一个CDatabase对象。如果CDatabase对象还没有连接到数据源,那么会在Open函数中建立连接,而连接字符串是由成员函数GetDefaultConnect提供的。

(2)virtual CString GetDefaultConnect();
该函数返回默认连接字符串。 Open函数在需要与数据源建立连接时会调用该函数来获取连接字符串。通常,您需要在 CRecordset 派生类中重写此函数,并在新版本的函数中提供连接字符串。
示例例如:CSetdata是CRecordset类的派生类
CString CSetdata::GetDefaultConnect()
{
return _T("ODBC;DSN=my data");
/>}
该函数获取数据库连接字符串,包括连接方式和数据源名称。

(3)virtual CString GetDefaultSQL();
Open函数在需要查询数据源中的记录时,会调用该函数返回默认的SQL语句或表名。一般来说,你需要重写这个函数n CRecordset 派生类并在新版本的函数中提供 SQL 语句或表名称。
例如:
CString CSetdata::GetDefaultSQL()
{
return _T("[bingli]");
}
该类返回数据源中数据表bingli的名称。

(4)virtual BOOL Open( UINT nOpenType = AFX_DB_USE_DEFAULT_TYPE, LPCTSTR lpszSQL = NULL, DWORD dwOptions = none );
throw( CDBException, CMemoryException );
该函数使用指定的SQL语句查询数据源中的记录,并根据指定的类型和选项创建记录集。参数nOpenType描述了记录集的类型,如下表所示。如果驱动程序不支持请求的类型,该函数将生成异常。参数 lpszSQL 是 SQL SELECT 语句或表名。该函数使用lpszSQL进行查询。如果该参数为NULL,则函数调用GetDefaultSQL来获取默认的SQL语句。参数eter dwOptions 可以是一些选项的组合。下表列出了常用的选项。如果创建成功,函数返回TRUE。如果函数调用 CDatabase::Open 并返回 FALSE,则函数返回 FALSE。

记录集类型
类型      
含义 
AFX_DB_USE_DEFAULT_TYPE 使用默认值。
CRecordset::dynaset 可以双向滚动的动态集。
CRecordset::snapshot 可以双向滚动的快照。
CRecordset::dynamic 提供比动态集更好的动态特性。大多数 ODBC 驱动程序不支持这种记录集。
CRecordset::forwardOnly 只读记录集,只能向前滚动。

创建记录集时常用的选项
选项                                                                                                                                                    
CRecordset::appendOnly 不允许修改删除记录,但可以添加记录。
CRecordset::readOnly 记录集是只读的。
CRecordset::skipDeletedRecords 有些数据库(如FoxPro)在删除记录时并不真正删除记录,而是做一个删除标记,并在滚动时跳过这些已删除的记录。

如果所有参数都为空,例如:
CSetdata *pset = new CSetdata();
pset->Open();
然后Open()函数会调用GetDefaultSQL()函数获取指定数据表的数据并创建数据集。事实上,如果只提供表名,CRecordset 类将构造一条 SELECT 语句来查询数据源。例如:SELECT
(可以提供的字段名)FROM bingli(即GetDefaultSQL()函数返回的表名)。

(5)建立记录集后,用户可以随时调用Requery成员函数重新查询并创建记录集。重新查询有两个重要目的:

使记录集能够反映用户对数据源的更改

查询记录并根据新的过滤或排序方法重新建立记录集。

在调用Requery之前,可以调用CanRestart判断记录集是否支持Requery操作。请记住,只有成功调用 Open 后才能调用 Requery,因此程序应调用 IsOpen 来确定记录集是否已建立。该函数声明为

virtual BOOL Requery( );
throw( CDBException, CMemoryException );
返回TRUE表示记录集建立成功,否则返回FALSE。如果函数内部发生错误,则会生成异常。

BOOL CanRestart() const; //如果支持Requery,则返回TRUE
BOOL IsOpen( ) const; //如果记录集已经建立,则返回TRUE

CRecordset类有两个公共数据成员m_strFilter和m_strSort用于set 记录的过滤和排序。在调用Open或Requery之前,如果在这两个数据成员中指定了过滤或排序,则Open和Requery将根据这两个数据成员指定的过滤和排序来查询数据源。
成员m_strFilter用于指定过滤器。 m_strFilter实际上包含SQLcontent的WHERE子句,但不包含WHERE关键字。使用 m_strFilter 的示例为:
m_pSet->m_strFilter="CourseID='MATH101'"; //只选择CourseID为MATH101的记录
if(m_pSet->Open(CRecordset::snapshot, "Section"))

. 。 。 。 。 .

成员m_strSort用于指定排序。 m_strSort实际上包含ORDER BY子句的内容,但不包含ORDER BY关键字。 m_strSort 的一个示例是

m_pSet->m_strSort="CourseID DESC"; //按照CourseID降序排列记录

m_pSet->Open();

. 。 。 。 。 .

其实当Open函数constr时当执行 SELECT 语句时,它会将 m_strFilter 和 m_strSort 的内容放入 SELECT 语句的 WHERE 和 ORDER
BY 子句中。如果Open的lpszSQL参数中已包含WHERE和ORDER BY子句,则m_strFilter和m_strSort必须为空。

调用无参数成员函数Close可以关闭记录集。调用Close函数后,程序可以再次调用Open来创建新的记录集。 CRecordset的析构函数调用Close函数,因此当CRecordset对象被删除时,记录集也被关闭。

4.滚动记录

CRecordset提供了几个用于在记录集中滚动的成员函数,如下所示。当您使用这些函数滚动到新记录时,框架会自动将新记录的内容复制到字段数据成员中。

无效 MoveNext(); //前进一条记录
void MovePrev(); //返回一条记录
void MoveFirst(); //滚动到记录集中的第一个Record
void MoveLast(); //滚动到记录集中的最后一条记录
void SetAbsolutePosition( long nRows);
该函数用于滚动到参数nRows指定的绝对位置。如果nRows为负数,则从后向前滚动。例如,当 nRows 为 -1 时,该函数滚动到记录集的末尾。请注意,此函数不会跳过已删除的记录。

virtual void Move(long nRows, WORD wFetchType = SQL_FETCH_RELATIVE);
这个功能很强大。通过指定wFetchType参数为SQL_FETCH_NEXT、SQL_FETCH_PRIOR、SQL_FETCH_FIRST、SQL_FETCH_LAST和SQL_FETCH_ABSOLUTE,即可完成以上五个函数的功能。如果wFetchType是SQL_FETCH_RELATIVE,它将相对于当前记录移动。如果nRows为正数,则向前移动。如果nRows为负数,则向后移动。

如果创建时选择 CRecordset::skipDeletedRecords 选项一个记录集,除了SetAbsolutePosition之外,滚动记录时会跳过已删除的记录。这对于像 FoxPro 这样的数据库非常重要。

如果记录集为空,调用上述函数将产生异常。另外,必须确保滚动不会超出记录集的边界。调用IsEOF和IsBOF可以检测到这一点。

BOOL IsEOF( ) const; //如果记录集为空或者最后一条记录已滚动,函数返回TRUE,否则返回FALSE。
BOOL IsBOF() const; //如果记录集为空或者第一条记录已滚动,函数返回TRUE,否则返回FALSE。

以下是使用 IsEOF 的示例:
while(!m_pSet->IsEOF( ))
m_pSet->MoveNext( );

调用 GetRecordCound可以获取记录集中的记录总数。该函数的声明为:
long GetRecordCount() const;
需要注意的是,这个函数返回的是我实际上是用户在记录集中滚动的最远距离。要实际返回记录总数,只能调用 MoveNext 移动到记录集的末尾(MoveLast 不起作用)。

5.修改、添加和删除记录

要修改当前记录,应遵循以下步骤:

调用Edit成员函数。调用该函数后,进入编辑模式,程序可以修改域数据成员。注意不要对空记录集调用Edit,否则会出现异常。

编辑函数会将当前域数据成员的内容保存在缓冲区中。这样做有两个目的。首先,它可以与域数据成员进行比较以确定哪些字段已被更改。其次,必要时可以恢复域数据成员的原始值。如果再次调用Edit,域数据成员将从缓冲区中恢复,程序仍处于编辑状态通话后模式。调用Move(AFX_MOVE_REFRESH)或Move(0)可以退出编辑模式(AFX_MOVE_REFRESH的值为0),同时该函数将从缓冲区中恢复域数据成员。

为域数据成员设置新值。

调用Update完成编辑。 Update 将更改的记录写入数据源并结束编辑模式。

要向记录集中添加一条新记录,应按照以下步骤操作:

调用AddNew成员函数。调用该函数后,就进入添加模式。该函数将所有域数据成员设置为NULL(注意,在数据库术语中,NULL表示没有值,这与C++的NULL不同)。与 Edit 一样,AddNew 会将当前域数据成员的内容保存在缓冲区中。必要时,程序可以再次调用AddNew来取消添加操作并恢复域数据成员的原始值。调用后,程序仍处于添加模式。 .调用移动(AFX_MOVE_REFRESH) 退出添加模式,该函数将从缓冲区中恢复域数据成员。

设置域数据成员。

致电更新。 Update将域数据成员的内容作为新记录写入数据源,从而结束添加。

如果记录集是快照,那么添加新记录后,需要调用Requery重新查询,因为快照无法体现添加操作。

要删除记录集中的当前记录,请执行以下两个步骤:

调用Delete成员函数。该函数将为记录集和数据源中的当前记录添加删除标记。注意不要对空记录集调用Delete,否则会产生异常。

滚动到另一条记录以跳过删除该记录。

上面提到的函数声明是:

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

virtual void AddNew( ); throw( CDBException );

虚拟无效删除e( ); throw( CDBException );

虚拟 BOOL Update( ); throw( CDBException );
如果更新失败,函数返回 FALSE ,并产生异常。

在对记录集进行更改之前,程序可能需要调用以下函数来判断该记录集是否可以更改,因为如果修改、添加或删除了不可更改的记录集,则会抛出异常会发生。 .

BOOL CanUpdate() const; //返回TRUE表示该记录可以修改、添加、删除。

BOOL CanAppend() const; //返回TRUE表示可以添加记录。

关于如何在ODBC中使用CRecordset类操作数据库的问题的答案就分享在这里。希望以上内容能够对大家有所帮助。如果您还有很多疑问,解锁吧,您可以关注行业资讯频道,了解更多相关知识。

1. 本站所有资源来源于用户上传或网络,仅作为参考研究使用,如有侵权请邮件联系站长!
2. 本站积分货币获取途径以及用途的解读,想在本站混的好,请务必认真阅读!
3. 本站强烈打击盗版/破解等有损他人权益和违法作为,请各位会员支持正版!
4. 编程技术 > ODBC中如何使用CRecordset类操作数据库

用户评论