Внедрение массовой выборки

В начале моей программы мне нужно прочитать данные из базы данных 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
      .
      .
      .
      .

Все, что мне нужно сделать, это только чтение данных из базы данных. Может кто-нибудь, пожалуйста, скажите мне, что я делаю неправильно? Мой код сейчас ведет себя точно как обычная выборка. Там не происходит массового извлечения.

EDIT:

Я просто ткнул в DBRFX.cpp и обнаружил, что RFX_Text_Bulk() инициализирует мой пройденный m_NameData как new char[nRowsetSize * nMaxLength]!

Это означает, что m_NameData - это только массив символов! Мне нужно получить несколько имен, так что мне не нужен 2D-массив символов? Самое странное, что те же RFX_Text_Bulk() инициализируют мой пройденный m_NDCDataLengths как new long[nRowsetSize]. Почему в мире массив символов должен иметь массив длин?!

Ответ 1

Ты почти все понял. Чтобы получить значения, Я бы изменил ваш

        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

EDIT 2: вы также можете сохранить CRecordset:: forwardonly, но добавьте опцию CRecordset:: useExtendedFetch

Ответ 2

Согласно http://msdn.microsoft.com/en-us/library/77dcbckz.aspx#_core_how_crecordset_supports_bulk_row_fetching, перед вызовом SetRowsetSize вам необходимо открыть CRecordset с помощью CRecordset:: useMultiRowFetch:

Чтобы реализовать массовую выборку строк, вы должны указать CRecordset:: useMultiRowFetch в параметре dwOptions Открыть функцию-член. Чтобы изменить настройку размера набора строк, вызовите SetRowsetSize.

Ответ 3

Просто столкнулся с той же проблемой. Вы должны использовать только recset.Open() для параметра dwOptions только CRecordset::useMultiRowFetch, а не CRecordset::readOnly | CRecordset::useMultiRowFetch. Надеюсь, это поможет кому-то...

РЕДАКТИРОВАТЬ: -. После повторной проверки здесь ситуация - при использовании массивного набора записей и открытия с помощью CRecordset::forwardOnly и CRecordset::readOnly вы также должны указать CRecordset::useExtendedFetch в dwOptions. Для других типов прокрутки использование CRecordset::readOnly | CRecordset::useMultiRowFetch просто отлично.