实现批量记录抓取

Implementing bulk record fetching

本文关键字:抓取 记录 实现      更新时间:2023-10-16

在我的程序开始时,我需要从MS Access数据库(.mdb)读取数据到下拉控件。这样做是为了无论何时用户在该控件中输入,应用程序都可以自动完成。

无论如何,从数据库读取花了很长时间,所以我想我应该实现批量行读取。

这是我的代码:

CString sDsn;
CString sField;
sDsn.Format("ODBC;DRIVER={%s};DSN='';DBQ=%s",sDriver,sFile);
TRY
{
    // Open the database
    database.Open(NULL,false,false,sDsn);
    // Allocate the rowset
    CMultiRowset recset( &database );
    // Build the SQL statement
    SqlString =  "SELECT NAME "
            "FROM INFOTABLE";
    // Set the rowset size. These many rows will be fetched in one bulk operation
    recset.SetRowsetSize(25);
    // Open the rowset
    recset.Open(CRecordset::forwardOnly, SqlString, CRecordset::readOnly | CRecordset::useMultiRowFetch);
    // Loop through each rowset
    while( !recset.IsEOF() )
    {
        int rowsFetched = (int)recset.GetRowsFetched(); // This value is always 1 somehow
        for( int rowCount = 1; rowCount <= rowsFetched; rowCount++ )
        {
            recset.SetRowsetCursorPosition(rowCount);
            recset.GetFieldValue("NAME",sField);
            m_nameDropDown.AddString(sField);
        }
        // Go to next rowset
        recset.MoveNext();
    }
    // Close the database
    database.Close();
}
CATCH(CDBException, e)
{
    // If a database exception occured, show error msg
    AfxMessageBox("Database error: "+e->m_strError);
}
END_CATCH;

MultiRowset.cpp看起来像:

#include "stdafx.h"
#include "afxdb.h"
#include "MultiRowset.h"
// Constructor
CMultiRowset::CMultiRowset(CDatabase *pDB)
   : CRecordset(pDB)
{
    m_NameData = NULL;
    m_NameDataLengths = NULL;
    m_nFields = 1;
    CRecordset::CRecordset(pDB);
}
void CMultiRowset::DoBulkFieldExchange(CFieldExchange *pFX)
{
   pFX->SetFieldType(CFieldExchange::outputColumn);
   RFX_Text_Bulk(pFX, _T("[NAME]"), &m_NameData, &m_NameDataLengths, 30);
}

MultiRowset.h看起来像:

#if !defined(__MULTIROWSET_H_AD12FD1F_0566_4cb2_AE11_057227A594B8__)
#define __MULTIROWSET_H_AD12FD1F_0566_4cb2_AE11_057227A594B8__
class CMultiRowset : public CRecordset
{
public:
      // Field data members
      LPSTR m_NameData;
      // Pointers for the lengths of the field data
      long* m_NameDataLengths;
      // Constructor
      CMultiRowset(CDatabase *);
      // Methods
      void DoBulkFieldExchange(CFieldExchange *);
};
#endif

在我的数据库中,INFOTABLE看起来像:

NAME    AGE
----    ---
Name1   Age1
Name2   Age2
      .
      .
      .
      .

所有我需要做的只是读取从数据库的数据。谁能告诉我我做错了什么吗?我的代码现在的行为就像一个正常的取回。没有批量抓取。

编辑:

我只是在DBRFX.cpp中戳了一下,发现RFX_Text_Bulk()将我传递的m_NameData初始化为new char[nRowsetSize * nMaxLength] !

这意味着m_NameData只是一个字符数组!我需要获取多个名称,所以我不需要一个2D字符数组吗?最奇怪的是,同样的RFX_Text_Bulk()将我传递的m_NDCDataLengths初始化为new long[nRowsetSize]。为什么字符数组需要长度数组?

根据http://msdn.microsoft.com/en-us/library/77dcbckz.aspx#_core_how_crecordset_supports_bulk_row_fetching你必须打开CRecordset与CRecordset::useMultiRowFetch标志之前调用SetRowsetSize:

要实现批量行抓取,必须指定参数dwOptions中的CRecordset::useMultiRowFetch选项打开成员函数。若要更改行集大小的设置,请调用SetRowsetSize .

你几乎答对了。要获取这些值,我会改变你的

        for( int rowCount = 1; rowCount <= rowsFetched; rowCount++ )
        {
            recset.SetRowsetCursorPosition(rowCount);
            recset.GetFieldValue("NAME",sField);
            m_nameDropDown.AddString(sField);
        }

被像这样的

for( int nPosInRowset = 0; nPosInRowset < rowsFetched; nPosInRowset++ )
{
    //Check if value is null
    if (*(recset.m_NameDataLengths + nPosInRowset) == SQL_NULL_DATA)
        continue;    
    CString csComboString;
    csComboString = (recset.m_NameData + (nPosInRowset * 30)); //Where 30 is the size specified in RFX_Text_Bulk
    m_nameDropDown.AddString(csComboString);
}

编辑:获取多行,删除CRecordset::forwardOnly选项

编辑2:您也可以保持CRecordset::forward - only,但添加CRecordset::useExtendedFetch选项

刚刚遇到了同样的问题。您应该在recset.Open()中使用dwOptions参数的CRecordset::useMultiRowFetch,而不是CRecordset::readOnly | CRecordset::useMultiRowFetch

EDIT:-重新检查后,这里是情况-当使用批量记录集并使用CRecordset::forwardOnlyCRecordset::readOnly打开时,您还必须在dwOptions中指定CRecordset::useExtendedFetch。对于其他类型的滚动,使用CRecordset::readOnly | CRecordset::useMultiRowFetch就可以了。