注释
自联机文档中首次包含此说明以来,尚未更新以下技术说明。 因此,某些过程和主题可能过期或不正确。 有关最新信息,建议在在线文档索引中搜索您感兴趣的主题。
此说明介绍如何使用 MFC 数据库类检索和发送 ODBC SQL_LONGVARCHAR 和 SQL_LONGVARBINARY 数据类型。
Long Varchar/Varbinary 支持概述
ODBC SQL_LONG_VARCHAR 和 SQL_LONGBINARY 数据类型(此处称为长数据列)可以容纳大量数据。 可通过 3 种方法处理此数据:
将其绑定到 .
CString
/CByteArray
将其绑定到 .
CLongBinary
不要完全绑定它,并手动检索和发送长数据值,与数据库类无关。
这三种方法中的每一个都有优点和缺点。
查询的参数不支持长数据列。 它们仅支持 outputColumns。
将长数据列绑定到 CString/CByteArray
优势:
此方法易于理解,并且你使用熟悉的类。 该框架提供 CFormView
对 CString
. DDX_Text
. 具有大量常规字符串或集合功能以及CString
CByteArray
类,可以控制本地分配的内存量来保存数据值。 框架在函数调用期间Edit
AddNew
维护字段数据的旧副本,框架可以自动检测对数据的更改。
注释
由于 CString
设计用于处理字符数据,并且 CByteArray
用于处理二进制数据,因此建议将字符数据(SQL_LONGVARCHAR) CString
和二进制数据(SQL_LONGVARBINARY)放入 CByteArray
其中。
RFX 函数具有CString
CByteArray
附加参数,可用于替代已分配内存的默认大小,以保存数据列的检索值。 请注意以下函数声明中的 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_Text
仅 RFX_Binary
使用 SQLFetch
一个调用从后端数据库检索数据。 每个 ODBC 驱动程序对可以在单个提取中返回的数据量有不同的限制。 此限制可能比 nMaxLength 中设置的值要小得多,在这种情况下,将引发 异常AFX_SQL_ERROR_DATA_TRUNCATED 。 在这些情况下,切换到“使用 RFX_LongBinary
”,而不是 RFX_Text
允许 RFX_Binary
检索所有数据。
ClassWizard 会将 SQL_LONGVARCHAR 绑定到 a CString
或 SQL_LONGVARBINARY 供 CByteArray
你使用。 如果要分配超过 255 个字节来检索长数据列,则可以为 nMaxLength 提供显式值。
当长数据列绑定到某个 CString
或 CByteArray
列时,更新字段的工作方式与绑定到 SQL_VARCHAR 或 SQL_VARBINARY 时相同。 在此期间 Edit
,将缓存数据值,稍后将进行比较, Update
以检测对数据值的更改,并相应地设置列的“脏”和“Null”值。
将长数据列绑定到 CLongBinary
如果长数据列可能包含更多 MAXINT 字节的数据,则应考虑将其检索到某个数据 CLongBinary
中。
优势:
这会检索整个长数据列,最多检索可用内存。
缺点:
数据保存在内存中。 对于大量数据,这种方法也非常昂贵。 必须调用 SetFieldDirty
绑定的数据成员,以确保字段包含在作中 Update
。
如果将长数据列检索到某个数据库中 CLongBinary
,数据库类将检查长数据列的总大小,然后分配 HGLOBAL
足够大的内存段来保存整个数据值。 然后,数据库类将整个数据值检索到分配 HGLOBAL
的数据值。
如果数据源无法返回长数据列的预期大小,框架将引发异常 AFX_SQL_ERROR_SQL_NO_TOTAL。 如果尝试分配 HGLOBAL
失败,则会引发标准内存异常。
ClassWizard 会将 SQL_LONGVARCHAR 或 SQL_LONGVARBINARY 绑定到你 CLongBinary
。 在“添加成员变量”对话框中选择 CLongBinary
为“变量类型”。 然后,ClassWizard 将添加 RFX_LongBinary
对 DoFieldExchange
调用的调用,并递增绑定字段的总数。
若要更新长数据列值,请先确保在HGLOBAL
m_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 文档的 SQLSetPos
rgbValue 参数)。 当框架准备插入或更新语句时,而不是指向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 检索/发送数据
使用此方法,可以完全绕过数据库类,并自行处理长数据列。
优势:
如有必要,可以将数据缓存到磁盘,或动态决定要检索的数据量。
缺点:
你没有得到框架 Edit
或 AddNew
支持,你必须自己编写代码来执行基本功能(Delete
不过,因为它不是列级作)。
在这种情况下,长数据列必须位于记录集的选择列表中,但不应绑定到框架。 执行此作的一种方法是通过 GetDefaultSQL
或作为 lpszSQL 参数 CRecordset
向函数 Open
提供自己的 SQL 语句,而不将额外的列与RFX_函数调用绑定。 ODBC 要求未绑定字段显示在绑定字段右侧,因此请将未绑定的列或列添加到选择列表的末尾。
注释
由于长数据列不受框架的约束,因此不会使用 CRecordset::Update
调用处理对它的更改。 必须自行创建和发送所需的 SQL INSERT 和 UPDATE 语句。