2013-03-01 14 views
10

All'inizio del mio programma, ho bisogno di leggere i dati da un database MS Access (.mdb) in un controllo a discesa. Questo viene fatto in modo che ogni volta che l'utente digita quel controllo, l'applicazione possa auto-completarsi.Implementazione del recupero di record di massa

In ogni caso, la lettura dal database è durata per sempre, quindi ho pensato di implementare il recupero di file alla rinfusa.

Questo è il codice che ho:

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 assomiglia:

#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 assomiglia:

#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 

E nel mio database, il INFOTABLE assomiglia:

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

Tutto ciò che devo fare è solo leggere i dati dal database. Qualcuno può dirmi cosa sto sbagliando? Il mio codice ora si comporta esattamente come un normale recupero. Non si verificano accuse di massa.

EDIT:

ho curiosato nel DBRFX.cpp e ho scoperto che il mio passato RFX_Text_Bulk() inizializza m_NameData come new char[nRowsetSize * nMaxLength]!

Ciò significa che m_NameData è solo un array di caratteri! Ho bisogno di recuperare più nomi, quindi non avrei bisogno di un array di caratteri 2D? La cosa più strana è che lo stesso RFX_Text_Bulk() inizializza il mio passaggio m_NDCDataLengths come new long[nRowsetSize]. Perché nel mondo un array di caratteri avrebbe bisogno di una serie di lunghezze ?!

+0

qual è la dimensione del campo "[NOME]" nel database? – Goldorak84

+0

@ Goldorak84, 15 caratteri max. –

+0

Infatti, m_NameData rappresenta una matrice di matrici di caratteri. m_NDCDataLengths rappresenta le lunghezze di ogni stringa in m_NameData – Goldorak84

risposta

2

Hai quasi capito bene. Per recuperare i valori, vorrei cambiare il vostro

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

da qualcosa di simile

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); 
} 

EDIT: per andare a prendere più di una riga, rimuovere il CRecordset :: ForwardOnly opzione

EDIT 2 : È inoltre possibile mantenere CRecordset :: forwardonly, ma aggiungere l'opzione CRecordset :: useExtendedFetch

+0

Ho provato questo. Il problema è che 'rowsFetched' è sempre 1! –

+0

Su che tipo di database ti stai connettendo? – Goldorak84

+0

È un database MS Access (.mdb) –

3

Secondo http://msdn.microsoft.com/en-us/library/77dcbckz.aspx#_core_how_crecordset_supports_bulk_row_fetching è necessario aprire CRecordset con CRecordset :: bandiera useMultiRowFetch prima chiamata SetRowsetSize:

Per attuare massa fetching fila, è necessario specificare l'opzione CRecordset :: useMultiRowFetch nel parametro del dwOptions Funzione membro aperto. Per modificare le impostazioni per la dimensione del set di righe, chiamare SetRowsetSize.

+0

Tale collegamento sembra essere interrotto. Anche da [questo articolo MSDN] (http://msdn.microsoft.com/en-us/library/77dcbckz (v = vs80) .aspx), "Dopo aver inizializzato la dimensione del set di righe, chiamare la funzione Apri membro . Qui devi specificare l'opzione CRecordset :: useMultiRowFetch'. Questo sembra contraddittorio. –

+1

Ho risolto il collegamento. Sì hai ragione. Prova a verificare che il recupero di massa sia implementato - chiama GetRowsetSize prima di SetRowsetSize: {quote} Prima di aprire l'oggetto recordset, puoi definire una dimensione di set di righe con la funzione membro SetRowsetSize. La dimensione del set di righe specifica il numero di record da recuperare durante un singolo recupero. Quando viene eseguito il recupero della raccolta di massa, la dimensione del set di righe predefinita è 25. Se non viene implementata la raccolta di file alla rinfusa, la dimensione del set di righe rimane fissa a 1. {quote} – AnatolyS

+0

La dimensione del set di righe sembra essere impostata correttamente. Al momento lo sto impostando su 25. 'Anche GetRowsetSize()' restituisce 25. –

0

Appena affrontato lo stesso problema. È necessario utilizzare la chiamata recset.Open() per il parametro dwOptions solo CRecordset::useMultiRowFetch e non CRecordset::readOnly | CRecordset::useMultiRowFetch. Spero che questo aiuti qualcuno ...

EDIT: - Dopo ricontrollare qui è la situazione - quando si utilizzano set di record di massa e l'apertura con CRecordset::forwardOnly e CRecordset::readOnly, è necessario specificare anche CRecordset::useExtendedFetch in dwOptions. Per altri tipi di scorrimento, usare CRecordset::readOnly | CRecordset::useMultiRowFetch va bene.

Problemi correlati