记录集:批量获取记录 (ODBC)

本主题适用于 MFC ODBC 类。

CRecordset 提供批量行提取支持,即,在单次提取期间可以一次性检索多条记录,而不是每次从数据源中检索一条记录。 只能在派生的 CRecordset 类中实现批量行提取。 将数据从数据源传输到记录集对象的过程称为批量记录字段交换(批量 RFX)。 请注意,如果不在 CRecordset 派生类中使用批量行提取,则数据将通过记录字段交换 (RFX) 来传输。 有关详细信息,请参阅记录字段交换 (RFX)

本主题介绍:

CRecordset 如何支持批量行提取

在打开记录集对象之前,可以使用 SetRowsetSize 成员函数定义行集大小。 行集大小指定在单次提取期间应检索多少条记录。 实现批量行提取时,默认行集大小为 25。 如果未实现批量行提取,则行集大小固定为 1。

初始化行集大小后,调用 Open 成员函数。 必须在此处指定 dwOptions 参数的 CRecordset::useMultiRowFetch 选项才能实现批量行提取。 此外,可以设置 CRecordset::userAllocMultiRowBuffers 选项。 批量记录字段交换机制使用数组来存储在提取期间检索到的多行数据。 这些存储缓冲区可以由框架自动分配,也可以由你手动分配。 指定 CRecordset::userAllocMultiRowBuffers 选项意味着由你进行分配。

下表列出了 CRecordset 提供的用于支持批量行提取的成员函数。

成员函数 说明
CheckRowsetError 处理提取期间发生的任何错误的虚拟函数。
DoBulkFieldExchange 实现批量记录字段交换。 自动调用以将多行数据从数据源传输到记录集对象。
GetRowsetSize 检索行集大小的当前设置。
GetRowsFetched 告知在完成给定的提取后实际检索了多少行。 在大多数情况下,除非提取了不完整的行集,否则这是行集大小。
GetRowStatus 返回行集中特定行的提取状态。
RefreshRowset 刷新行集中特定行的数据和状态。
SetRowsetCursorPosition 将光标移到行集中的特定行。
SetRowsetSize 用于将行集大小的设置更改为指定值的虚拟函数。

特殊注意事项

尽管批量获取行可以提高性能,但某些功能的工作方式不同。 在决定实现批量行提取之前,请注意以下事项:

  • 框架自动调用 DoBulkFieldExchange 成员函数将数据从数据源传输到记录集对象。 但是,数据不会从记录集传回到数据源。 调用 AddNewEditDeleteUpdate 成员函数会导致断言失败。 虽然 CRecordset 目前不提供更新批量数据行的机制,但你可以使用 ODBC API 函数 SQLSetPos 编写自己的函数。 有关 SQLSetPos 的详细信息,请参阅 ODBC 程序员参考

  • 成员函数 IsDeletedIsFieldDirtyIsFieldNullIsFieldNullableSetFieldDirtySetFieldNull 不可用于实现批量行提取的记录集。 但是,可以调用 GetRowStatus 来代替 IsDeleted,调用 GetODBCFieldInfo 来代替 IsFieldNullable

  • Move 操作按行集重新定位记录集。 例如,假设你打开了一个包含 100 条记录且初始行集大小为 10 的记录集。 Open 获取第 1 到第 10 行,当前记录定位在第 1 行。 MoveNext 调用获取下一个行集,而不是下一行。 此行集由第 11 到第 20 行组成,当前记录定位在第 11 行。 请注意,在实现批量行提取时,MoveNextMove( 1 ) 是不等效的。 Move( 1 ) 提取从当前记录中第 1 行开始的行集。 在此示例中,调用 Open 之后调用 Move( 1 ) 会获取由第 2 到第 11 行组成的行集,当前记录定位在第 2 行。 有关详细信息,请参阅 Move 成员函数。

  • 与记录字段交换不同,向导不支持批量记录字段交换。 这意味着,必须手动声明字段数据成员并通过编写批量 RFX 函数调用来手动重写 DoBulkFieldExchange。 有关详细信息,请参阅“类库参考”中的记录字段交换函数

如何实现批量记录字段交换

批量记录字段交换将数据行集从数据源传输到记录集对象。 批量 RFX 函数使用数组来存储此数据,并使用数组来存储行集中每个数据项的长度。 在类定义中,必须将字段数据成员定义为指针以访问数据数组。 此外,必须定义一组指针以访问长度数组。 不应将任何参数数据成员声明为指针;使用批量记录字段交换时声明参数数据成员与使用记录字段交换时声明参数数据成员的结果相同。 以下代码演示了一个简单的示例:

class MultiRowSet : public CRecordset
{
public:
   // Field/Param Data
      // field data members
      long* m_rgID;
      LPSTR m_rgName;

      // pointers for the lengths
      // of the field data
      long* m_rgIDLengths;
      long* m_rgNameLengths;

      // input parameter data member
      CString m_strNameParam;

   .
   .
   .
}

可以手动分配这些存储缓冲区,也可以让框架进行分配。 若要自行分配缓冲区,必须在 Open 成员函数中指定 dwOptions 参数的 CRecordset::userAllocMultiRowBuffers 选项。 确保将数组大小设置为至少等于行集大小。 如果你要让框架进行分配,应将指针初始化为 NULL。 此操作通常是在记录集对象的构造函数中完成的:

MultiRowSet::MultiRowSet( CDatabase* pDB )
   : CRecordset( pDB )
{
   m_rgID = NULL;
   m_rgName = NULL;
   m_rgIDLengths = NULL;
   m_rgNameLengths = NULL;
   m_strNameParam = "";

   m_nFields = 2;
   m_nParams = 1;

   .
   .
   .
}

最后,必须重写 DoBulkFieldExchange 成员函数。 对字段数据成员调用批量 RFX 函数;对任何参数数据成员调用 RFX 函数。 如果通过将 SQL 语句或存储过程传递给 Open 打开了记录集,则批量 RFX 调用顺序必须与记录集中列的顺序相对应;同样,对参数的 RFX 调用顺序必须与 SQL 语句或存储过程中的参数顺序相对应。

void MultiRowSet::DoBulkFieldExchange( CFieldExchange* pFX )
{
   // call the Bulk RFX functions
   // for field data members
   pFX->SetFieldType( CFieldExchange::outputColumn );
   RFX_Long_Bulk( pFX, _T( "[colRecID]" ),
                  &m_rgID, &m_rgIDLengths );
   RFX_Text_Bulk( pFX, _T( "[colName]" ),
                  &m_rgName, &m_rgNameLengths, 30 );

   // call the RFX functions for
   // for parameter data members
   pFX->SetFieldType( CFieldExchange::inputParam );
   RFX_Text( pFX, "NameParam", m_strNameParam );
}

注意

必须在派生的 CRecordset 类超出范围之前调用 Close 成员函数。 这可以确保释放框架分配的任何内存。 无论是否实现了批量行提取,始终显式调用 Close 都是良好的编程做法。

有关记录字段交换 (RFX) 的详细信息,请参阅记录字段交换:RFX 的工作原理。 有关如何使用参数的详细信息,请参阅 CFieldExchange::SetFieldType记录集:参数化记录集 (ODBC)

另请参阅

记录集 (ODBC)
CRecordset::m_nFields
CRecordset::m_nParams