TN045:对 Long Varchar/Varbinary 的 MFC/数据库支持

注释

自联机文档中首次包含此说明以来,尚未更新以下技术说明。 因此,某些过程和主题可能过期或不正确。 有关最新信息,建议在在线文档索引中搜索您感兴趣的主题。

此说明介绍如何使用 MFC 数据库类检索和发送 ODBC SQL_LONGVARCHARSQL_LONGVARBINARY 数据类型。

Long Varchar/Varbinary 支持概述

ODBC SQL_LONG_VARCHARSQL_LONGBINARY 数据类型(此处称为长数据列)可以容纳大量数据。 可通过 3 种方法处理此数据:

  • 将其绑定到 .CString/CByteArray

  • 将其绑定到 .CLongBinary

  • 不要完全绑定它,并手动检索和发送长数据值,与数据库类无关。

这三种方法中的每一个都有优点和缺点。

查询的参数不支持长数据列。 它们仅支持 outputColumns。

将长数据列绑定到 CString/CByteArray

优势:

此方法易于理解,并且你使用熟悉的类。 该框架提供 CFormViewCString . DDX_Text. 具有大量常规字符串或集合功能以及CStringCByteArray类,可以控制本地分配的内存量来保存数据值。 框架在函数调用期间EditAddNew维护字段数据的旧副本,框架可以自动检测对数据的更改。

注释

由于 CString 设计用于处理字符数据,并且 CByteArray 用于处理二进制数据,因此建议将字符数据(SQL_LONGVARCHARCString和二进制数据(SQL_LONGVARBINARY)放入 CByteArray其中。

RFX 函数具有CStringCByteArray附加参数,可用于替代已分配内存的默认大小,以保存数据列的检索值。 请注意以下函数声明中的 nMaxLength 参数:

void AFXAPI RFX_Text(CFieldExchange* pFX,
    const char *szName,
    CString& value,
    int nMaxLength = 255,
    int nColumnType =
    SQL_VARCHAR);

void AFXAPI RFX_Binary(CFieldExchange* pFX,
    const char *szName,
    CByteArray& value,
    int nMaxLength = 255);

如果将长数据列检索到某个 CString 数据列,则 CByteArray默认返回的最大数据量为 255 字节。 超出此范围的任何内容将被忽略。 在这种情况下,框架将引发 异常AFX_SQL_ERROR_DATA_TRUNCATED。 幸运的是,可以将 nMaxLength 显式增加到更大的值,最多可以增加 MAXINT

注释

MFC 使用 nMaxLength 的值来设置函数的 SQLBindColumn 本地缓冲区。 这是用于存储数据的本地缓冲区,实际上不会影响 ODBC 驱动程序返回的数据量。 RFX_TextRFX_Binary 使用 SQLFetch 一个调用从后端数据库检索数据。 每个 ODBC 驱动程序对可以在单个提取中返回的数据量有不同的限制。 此限制可能比 nMaxLength 中设置的值要小得多,在这种情况下,将引发 异常AFX_SQL_ERROR_DATA_TRUNCATED 。 在这些情况下,切换到“使用 RFX_LongBinary ”,而不是 RFX_Text 允许 RFX_Binary 检索所有数据。

ClassWizard 会将 SQL_LONGVARCHAR 绑定到 a CStringSQL_LONGVARBINARYCByteArray 你使用。 如果要分配超过 255 个字节来检索长数据列,则可以为 nMaxLength 提供显式值。

当长数据列绑定到某个 CStringCByteArray列时,更新字段的工作方式与绑定到 SQL_VARCHAR 或 SQL_VARBINARY 时相同。 在此期间 Edit,将缓存数据值,稍后将进行比较, Update 以检测对数据值的更改,并相应地设置列的“脏”和“Null”值。

将长数据列绑定到 CLongBinary

如果长数据列可能包含更多 MAXINT 字节的数据,则应考虑将其检索到某个数据 CLongBinary中。

优势:

这会检索整个长数据列,最多检索可用内存。

缺点:

数据保存在内存中。 对于大量数据,这种方法也非常昂贵。 必须调用 SetFieldDirty 绑定的数据成员,以确保字段包含在作中 Update

如果将长数据列检索到某个数据库中 CLongBinary,数据库类将检查长数据列的总大小,然后分配 HGLOBAL 足够大的内存段来保存整个数据值。 然后,数据库类将整个数据值检索到分配 HGLOBAL的数据值。

如果数据源无法返回长数据列的预期大小,框架将引发异常 AFX_SQL_ERROR_SQL_NO_TOTAL。 如果尝试分配 HGLOBAL 失败,则会引发标准内存异常。

ClassWizard 会将 SQL_LONGVARCHARSQL_LONGVARBINARY 绑定到你 CLongBinary 。 在“添加成员变量”对话框中选择 CLongBinary 为“变量类型”。 然后,ClassWizard 将添加 RFX_LongBinaryDoFieldExchange 调用的调用,并递增绑定字段的总数。

若要更新长数据列值,请先确保在HGLOBALm_hData成员CLongBinary上调用 ::GlobalSize 来保存新数据。 如果太小,请 HGLOBAL 释放并分配适当的大小。 然后设置 m_dwDataLength 以反映新大小。

否则,如果 m_dwDataLength 大于要替换的数据的大小,则可以释放和重新分配 HGLOBAL数据,或将其保留分配。 请确保指示实际在 m_dwDataLength中使用的字节数。

更新 CLongBinary 的工作原理

无需了解更新 CLongBinary 工作原理,但如果选择以下第三种方法,则将其作为如何将长数据值发送到数据源的示例可能很有用。

注释

若要在 CLongBinary 更新中包含字段,必须显式调用 SetFieldDirty 该字段。 如果对字段进行任何更改,包括将其设置为 Null,则必须调用 SetFieldDirty。 还必须调用 SetFieldNull第二个参数为 FALSE,才能将字段标记为具有值。

更新 CLongBinary 字段时,数据库类使用 ODBC 的 DATA_AT_EXEC 机制(请参阅 ODBC 文档的 SQLSetPosrgbValue 参数)。 当框架准备插入或更新语句时,而不是指向HGLOBAL包含数据,而是将列的CLongBinary地址设置为列的值,并将长度指示器设置为SQL_DATA_AT_EXEC。 稍后,将 update 语句发送到数据源时, SQLExecDirect 将返回 SQL_NEED_DATA。 这会提醒框架,此列的参数值实际上是一个 CLongBinary地址。 框架使用小缓冲区调用 SQLGetData 一次,期望驱动程序返回数据的实际长度。 如果驱动程序返回二进制大型对象(BLOB)的实际长度,MFC 将重新分配尽可能多的空间来提取 BLOB。 如果数据源返回 SQL_NO_TOTAL,指示它无法确定 BLOB 的大小,MFC 将创建较小的块。 默认的初始大小为 64K,后续块的大小将为两倍;例如,第二个为 128K,第三个为 256K,依依如此。 初始大小可配置。

未绑定:使用 SQLGetData 直接从 ODBC 检索/发送数据

使用此方法,可以完全绕过数据库类,并自行处理长数据列。

优势:

如有必要,可以将数据缓存到磁盘,或动态决定要检索的数据量。

缺点:

你没有得到框架 EditAddNew 支持,你必须自己编写代码来执行基本功能(Delete 不过,因为它不是列级作)。

在这种情况下,长数据列必须位于记录集的选择列表中,但不应绑定到框架。 执行此作的一种方法是通过 GetDefaultSQL 或作为 lpszSQL 参数 CRecordset向函数 Open 提供自己的 SQL 语句,而不将额外的列与RFX_函数调用绑定。 ODBC 要求未绑定字段显示在绑定字段右侧,因此请将未绑定的列或列添加到选择列表的末尾。

注释

由于长数据列不受框架的约束,因此不会使用 CRecordset::Update 调用处理对它的更改。 必须自行创建和发送所需的 SQL INSERTUPDATE 语句。

另请参阅

按编号列出的技术说明
按类别列出的技术说明