草庐IT

c++ - 指定 useMultiRowFetch 时,自定义 CRecordset 类不调用 DoFieldExchange()

coder 2024-02-05 原文

我已经实现了一个自定义的 CRecordset 类,并且具有类似于以下的代码:

ASSERT(prs->GetRowsetSize() == 25);
while (!prs->IsEOF())
{
    for (int i = 1; i <= prs->GetRowsFetched(); i++)
    {
        prs->SetRowsetCursorPosition((WORD)i);

        // Inspecting data here...

    }
    prs->MoveNext();
}
prs->Close();

显然,当使用多行提取时,CRecordset 不会像不使用多行提取时那样调用我的 DoFieldExchange 重写,这是设计使然。所以我的数据不会自动填充。那么问题是如何获取数据?

答案似乎是调用 GetFieldValue()。但是当我这样做时,我得到了一个无效的光标位置错误! (当我不使用多行提取时,GetFieldValue() 工作正常。)

下面是我的记录集类的简化版本。此外,@EylM 非常擅长在下面的答案中创建一个示例,他说确实对他有用。但是,当我完全复制他的代码并更改连接和查询我的数据库所需的内容时,我仍然在调用 GetFieldValue 时得到一个无效的光标位置 ()

我不知道还有什么不同。我看到他在使用 MySQL 而我在使用 SQL Server。但肯定 CRecordset 与 SQL Server 一起工作。我还尝试了所有可用的 SQL Server ODBC 驱动程序,但结果总是一样。

class CRS : public CRecordset
{
public:
    // Data variables
    int m_nId;
    TCHAR m_szName[CUSTOMER_NAME_MAXLENGTH + 1];

    // Bulk data variables
    int* m_pnIds;
    long* m_pnIdLengths;
    LPTSTR m_pszNames;
    long* m_pnNameLengths;

    // Constructor
    CRS(CDatabase* pDatabase = NULL)
        : CRecordset(pDatabase)
    {
        m_nFields = 2;

        m_nId = 0;
        m_szName[0] = '\0';

        m_pnIds = NULL;
        m_pnIdLengths = NULL;
        m_pszNames = NULL;
        m_pnNameLengths = NULL;
    }

    CString GetDefaultSQL()
    {
        return CCustomerData::m_szTableName;
    }

    // This method is never called when
    // CRecordset::useMultiRowFetch is specified!
    void DoFieldExchange(CFieldExchange* pFX)
    {
        pFX->SetFieldType(CFieldExchange::outputColumn);
        RFX_Int(pFX, _T("Id"), m_nId);
        RFX_Text(pFX, _T("Name"), m_szName, CUSTOMER_NAME_MAXLENGTH);
    }

    // This method is called several times
    void DoBulkFieldExchange(CFieldExchange* pFX)
    {
        pFX->SetFieldType(CFieldExchange::outputColumn);
        RFX_Int_Bulk(pFX, _T("Id"), &m_pnIds, &m_pnIdLengths);
        RFX_Text_Bulk(pFX, _T("Name"), &m_pszNames, &m_pnNameLengths, (CUSTOMER_NAME_MAXLENGTH + 1) * 2);
    }
};

更新:

在这上面花更多的时间,我已经能够编写直接从行集数据读取数据的代码(在我的例子中,从 m_pnIdsm_pnIdLengthsm_pszNamesm_pnNameLengths)。也许这就是我需要采取的方法。

但问题仍然存在。为什么我不能在 SQL Server 数据库上使用 GetFieldValue()SetRowsetCursorPosition() 的意义何在?

最佳答案

来自 CRecordset::DoFieldExchange 的文档:

When bulk row fetching is not implemented, the framework calls this member function to automatically exchange data between the field data members of your recordset object and the corresponding columns of the current record on the data source.

仅当 Open 函数中未指定 CRecordset::useMultiRowFetch 时,才会调用

DoFieldExchange。 查看 MFC 代码 CRecordset::BindFieldsToColumns,使用 VS 2019 (14.22.27905) 的 dbcore.cpp:

// Binding depends on fetch type
if (m_dwOptions & useMultiRowFetch)
    DoBulkFieldExchange(&fx);
else
    DoFieldExchange(&fx);

听起来您的行为是设计使然。

编辑:

这里是多行获取的工作示例。解决问题的方法是打开标志中的 CRecordset::useExtendedFetch

数据库: 我将 MySQL 与一个包含 2 列的简单表一起使用。这是创建脚本。

CREATE TABLE `categories` (
  `CatID` int(11) NOT NULL,
  `Category` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  PRIMARY KEY (`CatID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

MFC:

CMultiRowSet.h
class CMultiRowSet : public CRecordset
{   
public:
    CMultiRowSet(CDatabase* pDB);

    virtual void DoBulkFieldExchange(CFieldExchange* pFX);

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

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

用法:

CDatabase database; 
CString sCatID, sCategory;

TRY
{
    CString connStr = (_T("Driver={MySQL ODBC 8.0 Unicode Driver};Server=localhost;Database=XXXX;User=XXX; Password=XXXX; Option = 3;"));

    // Open the database
    database.OpenEx(connStr,CDatabase::noOdbcDialog);

    // Allocate the recordset
    CMultiRowSet recset(&database);     

    // Execute the query
    // make sure you use CRecordset::useExtendedFetch.
    recset.Open(CRecordset::forwardOnly, _T("SELECT CatID, Category FROM Categories"), CRecordset::readOnly|CRecordset::useMultiRowFetch|CRecordset::useExtendedFetch);

    // Loop through each record
    while (!recset.IsEOF())
    {       
        // The default `GetRowsetSize` is 25. I have 4 rows in my database. 
        // GetRowsFetched returns 4 in my case.
        for (int rowCount = 1; rowCount <= (int)recset.GetRowsFetched(); rowCount++)
        {           
            recset.SetRowsetCursorPosition(rowCount);

            // Copy each column into a variable
            recset.GetFieldValue(_T("CatID"), sCatID);
            recset.GetFieldValue(_T("Category"), sCategory);
        }

        // goto next record
        recset.MoveNext();
    }

    recset.Close();

    // Close the database
    database.Close();
}
CATCH(CDBException, e)
{
    // If a database exception occured, show error msg
    AfxMessageBox(_T("Database error: ") + e->m_strError);
}
END_CATCH;

关于c++ - 指定 useMultiRowFetch 时,自定义 CRecordset 类不调用 DoFieldExchange(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57649696/

有关c++ - 指定 useMultiRowFetch 时,自定义 CRecordset 类不调用 DoFieldExchange()的更多相关文章

  1. ruby - Facter::Util::Uptime:Module 的未定义方法 get_uptime (NoMethodError) - 2

    我正在尝试设置一个puppet节点,但ruby​​gems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由ruby​​gems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby

  2. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  3. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  4. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  5. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

    我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

  6. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  7. ruby-on-rails - 在 ruby​​ .gemspec 文件中,如何指定依赖项的多个版本? - 2

    我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这

  8. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

    我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

  9. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  10. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

随机推荐