2013-03-01 25 views
10

在我的程序开始时,我需要将数据从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_NameDatanew char[nRowsetSize * nMaxLength]

这意味着m_NameData只是一个字符数组!我需要获取多个名称,所以我不需要一个2D字符数组?最奇怪的是,RFX_Text_Bulk()初始化我的m_NDCDataLengthsnew long[nRowsetSize]。为什么在世界上一个字符数组需要一个长度数组?

+0

数据库中“[NAME]”字段的大小是多少? – Goldorak84 2013-04-01 13:38:52

+0

@ Goldorak84,最多15个字符。 – 2013-04-02 10:28:55

+0

实际上,m_NameData表示一个字符数组的数组。 m_NDCDataLengths表示m_NameData中的每个字符串的长度。 – Goldorak84 2013-04-02 13:59:13

回答

2

你几乎说得没错。为了获取价值, 我会改变你的

 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选项

+0

我确实尝试过。问题是,'rowsFetched'总是1! – 2013-04-02 15:10:09

+0

您连接的是哪种数据库? – Goldorak84 2013-04-02 15:31:46

+0

这是一个MS Access数据库(.mdb) – 2013-04-02 15:37:45

3

根据http://msdn.microsoft.com/en-us/library/77dcbckz.aspx#_core_how_crecordset_supports_bulk_row_fetching你有电话SetRowsetSize之前的CRecordset打开的CRecordset :: useMultiRowFetch标志:

要实现批量取行,你必须指定的的dwOptions参数 的CRecordset :: useMultiRowFetch选项 打开会员功能。要更改行集大小的设置,请拨打 SetRowsetSize。

+0

该链接似乎被破坏。也可以从[此MSDN文章](http://msdn.microsoft.com/zh-cn/library/77dcbckz(v = vs80).aspx),'在初始化行集大小后,调用Open成员函数。在这里你必须指定CRecordset :: useMultiRowFetch选项。这似乎是矛盾的。 – 2013-03-05 09:22:51

+1

我已修复链接。是的,你是对的。尝试检查是否实现了批量获取 - 在SetRowsetSize之前调用GetRowsetSize:{quote}在打开记录集对象之前,可以使用SetRowsetSize成员函数定义行集大小。行集大小指定在单个提取期间应检索多少条记录。当实现批量行读取时,默认行集大小为25.如果未实施批量行读取,则行集大小保持固定为1. {quote} – AnatolyS 2013-03-05 09:32:52

+0

行集大小似乎设置正确。目前我将它设置为25。 'GetRowsetSize()'也返回25。 – 2013-03-05 09:52:33

0

刚刚面临同样的问题。 您应该使用recset.Open()呼叫dwOptions参数只有CRecordset::useMultiRowFetch,而不是CRecordset::readOnly | CRecordset::useMultiRowFetch。 希望这可以帮助别人......

编辑: -后重新检查这里的情况是 - 使用大容量记录,并与CRecordset::forwardOnlyCRecordset::readOnly开放时,你还必须在dwOptions指定CRecordset::useExtendedFetch。对于其他类型的滚动,使用CRecordset::readOnly | CRecordset::useMultiRowFetch就好了。