帮酷LOGO
0 0 评论
文章标签:附加  插入  ADO  ADOX  字段  

Sample Image - ADOXInsertField.gif

介绍

不可能使用plain附加列方法插入字段( 就像 MS Access )。 原因如下:

  • 当然,Append 只会在集合的末尾添加一列;
  • 字段/列的集合按字母顺序排列。

本文提供了一种使用ADOX以编程方式将字段插入 MS Access 数据库表的方法。 还有其他的方法 修改表 但使用ADOX非常吸引人,因为它允许访问提供程序特定的字段属性,如描述。默认值。自动增量。nullable。allow-zero-length等等。

鏂规碜

方法非常简单: 重建表格 !

  • 创建空临时表
  • 使用正确序号顺序从原始表中复制每个字段。 在到达插入点时追加要插入的字段。
  • 将原始表中的记录复制到临时表中
  • 将索引复制到临时表
  • *Copy/Restore 其他表属性或者对象如果有
  • *Temporarily 从关系中删除原始表( MSysRelationships )
  • 删除原始表
  • 将临时表重命名为原始表的NAME
  • 表的*Restore 原始关系

在本文或者代码示例中处理的*Not。

重建表格实际上并不是那么简单。 这里要解决的第一个问题是字段集合按字母顺序排序字段。 解决方案已经在另一篇文章中介绍: 获取ADOX表对象的正确列序号。

此外,提供程序有自己的特殊表和字段属性。 在重建表时,请确保正确还原了应用程序使用的属性。 这可能是一个case-by-case基础,因此本文不进一步讨论细节。 ( 在代码中请参见限制部分和代码中的TODO项,以了解改进和专门化

<沙箱> 很好,对于纯粹,方法是纯丑陋的。 我也不喜欢它,但是它工作得很好,而且我的项目也很好地工作。 我只希望本文成为更好解决方案的起点。 </沙箱>

使用代码

下面是函数 Prototype:

static BOOL InsertField(_TablePtr p_table, 
 _ColumnPtr p_field, long l_beforeIndex, _bstr_t & rstr_error)

在指定序号位置之前插入新字段。

参数
  • OField & p_newField - 对新 OField 对象的引用
  • long l_beforeIndex - 在这里位置插入新字段
  • _bstr_t & rstr_error - 对将收到错误消息的字符串的引用,如果有的话
返回
  • BOOL - 如果成功插入了字段,则为 TRUE
便笺

新字段应该具有默认值,或者"可为空值"属性应设置为 TRUE,否则插入操作将失败。 当临时表填充了表的原始记录后,新的字段值就是 ( 如果未给出默认值)。

你需要将文件 ADOXInsertField.h 包含到项目中;或者复制粘贴到你的类中。 文件 ADOXColumnOrdinal.h 是必需的,并且也包含在这个包中。

注意:如果还没有设置,你需要设置/GX 编译器选项来支持异常处理。

请确保你的stdafx.h 或者其他地方有以下内容。

// I assume you have this somewhere#import "C:Program FilesCommon FilesSystemadomsado15.dll" 
 rename( "EOF", "adoEOF" ) rename("DataTypeEnum", "adoDataTypeEnum")
#import "C:Program FilesCommon FilesSystemadomsadox.dll" 
 rename( "EOF", "adoEOF" ) no_namespace rename("DataTypeEnum", 
 "adoDataTypeEnum")// For _bstr_t and _variant_t<#include <comdef.h>// OLEDB<#include "oledb.h"// And of course, our code<#include "ADOXInsertField.h"

例子

下面的代码在字段 Value 当前持有的序号位置插入一个名为 Quality的新字段。

_TablePtr p_table = mp_catalog->Tables->GetItem(_T("MyTable"));// Get a conversion map from ADOX collection index into actual field ordinalColumnNameToOrdinal columnMap;if (GetColumnNameToOrdinalMap(p_table, columnMap))
{
 // Here is the field we want to insert _ColumnPtr fieldToAdd;
 fieldToAdd.CreateInstance(__uuidof (Column));
 // Set the reference catalog so that we can access Jet OLEDB properties fieldToAdd->PutRefParentCatalog(mp_catalog);
 // Field Name fieldToAdd->PutName(_T("Quality"));
 // Description of the field fieldToAdd->Properties->GetItem
 (_T("Description"))->PutValue(_T("Quality assessment"));
 // Field Type fieldToAdd->PutType(adVarWChar);
 // Field Size fieldToAdd->PutDefinedSize(64);
 // Nullable fieldToAdd->Properties->GetItem
 (_T("Nullable"))->PutValue
 (_variant_t(VARIANT_TRUE,VT_BOOL));
 // Allow Zero Length  fieldToAdd->Properties->GetItem
 (_T("Jet OLEDB:Allow Zero Length"))->PutValue
 (_variant_t(VARIANT_TRUE,VT_BOOL));
 // Default Value  fieldToAdd->Properties->GetItem
 (_T("Default"))->PutValue(_bstr_t("Not assessed"));
 // Now do the insert thing _bstr_t str_error;
 if (InsertField(p_table, fieldToAdd, 
 columnMap[_T("Value")], str_error))
 {
 // Note! p_table is no longer valid// because it is pointing to a table that has // already been replaced by a new one containing the inserted field// So get it again p_table = mp_catalog->Tables->GetItem(_T("MyTable"));
 }
 else {
 ::MessageBox(NULL, str_error,_T("Insert"), 
 MB_ICONINFORMATION|MB_OK);
 }
}

限制,从这里到哪里

  • InsertField 不能在包含 BLOB s 或者 长二进制数据 这是由于临时表是由标准的SQL语句填充的。 你可能需要使用 ado/oledb方法来传送 BLOB 在桌子之间。
  • 只支持以下字段属性集合项:
  • 默认值
  • 描述
  • 可为空值
  • Jet OLEDB: 允许零长度

为了改进代码,你可以在 CopyFieldProperties 函数中添加对以下代码的支持。

  • 自动增量
  • 固定长度
  • 种子
  • 增量
  • Jet OLEDB:Column 验证文本
  • Jet OLEDB:Column 验证规则
  • Jet OLEDB:IISAM 不是最后一列
  • Jet OLEDB:AutoGenerate
  • 每秒 Jet OLEDB:One BLOB
  • Jet OLEDB:Compressed UNICODE字符串
  • Jet OLEDB:Hyperlink
  • 在关系中使用的表不工作。 这可以通过扫描 MSysRelationShipsszObjects 字段。如果表存在,上面的步骤 7将失败。 要使它正常工作,你必须找出如何删除和恢复条目( 步骤 6和 9 )。

观测值

当从原始表复制字段属性到临时表时,遇到了大多数问题。 以下是最痛苦的:

空字段属性异常

在某些 Jet OLE DB配置( 2.5或者 2.6与 MS Access 安装混合) 上,列属性集合中的"可为空值"属性反转。 例如:将"可为空值"设置为 TRUE 在添加列之后,获取"可为空值"属性后,你将得到 FALSE 尽管它被设置为 TRUE 当你从 MS Access 看它时。

在读取"可为空值"属性时,请使用 GetAttributes 方法:

BOOL b_nullable = p_sourceField->GetAttributes()&adColNullable;

但是,在设置"可为空值"属性时,请使用字段属性集合:

p_targetField->Properties->GetItem(_T("Nullable"))->PutValue
 (_variant_t(VARIANT_TRUE,VT_BOOL));

那么为什么不完全使用 Get/PutAttributes? 答:因为使用 p_field->PutAttributes() 方法设置"可为空值"属性将在将字段追加到集合中时导致异常。 请参见图:- (

不要触摸我的属性 !

在传递属性集合时,只需循环到集合并将它的设置为其他字段。 这样,我将不会在上面的限制部分中列出 #2 项目。 例如:

for (long i = 0; i < p_source->Properties->GetCount(); i++)
{
 _variant_t var_prop;
 _bstr_t name = p_source->Properties->GetItem(i)->GetName();
 ATLTRACE(_T("Field Property %d: %sn"), i+1, (LPCTSTR)name);
 try {
 var_prop = p_source->Properties->GetItem(i)->GetValue();
 if (var_prop.vt!= VT_EMPTY && var_prop.vt!= VT_NULL)
 {
 p_destination->Properties->GetItem(i)->PutValue(var_prop);
 }
 }
 catch(...)
 {
 }
}

上面的代码将运行正常,但是当我们最终将字段( p_destination ) 添加到表中时, OLEDB 0 x80040e21 - 连续错误。 是一个敏感的属性集合,它不希望你触摸不与字段相关的属性? 我没有更多时间来解决这个问题,所以我将它留给你们,告诉我们发生了什么。

为了解决这个问题,CopyFieldProperties() 只复制选择的属性,然后在这样做之前测试字段类型的相关性。 关于支持哪些属性,请参见限制部分。

演示应用程序

示例项目是一个简单的ATL应用程序。 它只是为了展示 InsertField 如何工作,但是它已经成长为支持浏览字段属性和删除字段。 总之,在演示项目中,你可以看到一点:

  • 使用ADO和 ADOX
  • 使用 ADOX 目录 , 表格 对象
  • 正在扫描OLEDB提供程序错误
  • 列出列表视图控件的基本方法
  • WTL中的反射,通知处理
  • 在 atl/WTL中使用 DDX
  • 当然,使用 ADOXColumnOrdinal.h 和 ADOXInsertField.h

便笺

  • base应用程序是使用版本 7的向导生成的。
  • 编译发布模式时,必须删除项目设置中定义的_ATL_MIN_CRT 以解决 链接错误:未找到 LNK2001 符号'_main'main() 入口点是STL需要的。
  • 启用/GX 选项,以支持异常处理
  • 如果要使用 AtlInitCommonControls() 版本 3编译它,请用 ADOXInsertField.cpp 文件中的注释掉行。

最终

最后,我可以说- 在我烹饪晚餐时,这里写的代码是写的:。 它可能不是完美的,但我希望它有助于说明我的观点。

历史记录

  • 2 2003年月 - 包含 ADOXColumnOrdinal.h 中的更改,以动态检测书签支持
  • 8 2003年05月 - 初始版本


文章标签:ADO  字段  插入  附加  ADOX  

Copyright © 2011 HelpLib All rights reserved.    知识分享协议 京ICP备05059198号-3  |  如果智培  |  酷兔英语