使 ATL OLE DB 提供程序模板支持数据更新 - 第 2 部分





5.00/5 (1投票)
ATL OLE DB 提供程序模板似乎仅支持只读行集,并且使其支持数据更新不像您期望的那样容易!
客户端游标引擎更新
事实证明,通过客户端游标引擎支持更新相对容易。认识到这一点相对容易却极其困难。MSDN 中一篇新添加的文章提供了关于行集需要支持哪些才能通过 CCE 进行更新的完整信息。在此文章发布之前,您必须依赖猜测来找出如何实现……顺便说一句,如果微软的任何人读到这篇文章,那篇客户端游标引擎文章真的很棒,我们需要更多具有这种技术信息水平的文章。
A9645971-91EE-11D1-9251-00C04FBBBFB3
我probably花了大约 6 个月的时间才让客户端游标更新生效。我尝试添加 IRowsetUpdate,这是一个显而易见的选择,但完全没有必要。我尝试添加各种其他接口,凭空猜测但完全失败。客户端游标更新的主要问题是,当出现令人讨厌的“更新或刷新所需的基表信息不足”消息时,会查询您的 OLE DB 提供程序的会话对象以获取一个未公开的接口。IID 是 {A9645971-91EE-11D1-9251-00C04FBBBFB3}
,根据微软支持人员的说法,该接口是关于更新不支持 SQL 的提供程序的文档错误的受害者。
那么,秘密是什么
事实证明,要消除“信息不足……”错误消息,您需要做的就是实现 IColumnsRowset,这并不难,因为大多数所需信息都可以通过调用 IColumnsInfo::GetColumnInfo
来获得,而 ATL 模板支持该方法。实现 IColumnsRowset
的主要问题是 GetAvailableColumns
必须至少返回以下三个可选的元数据列
DBCOLUMN_BASECOLUMNNAME
DBCOLUMN_KEYCOLUMN
<LI><CODE>DBCOLUMN_BASETABLENAME
并且 GetColumnsRowset
必须返回一个行集,其中包含这些可选的元数据列并包含有效信息。
在当前情况下,表名实际上并不重要,因此我们可以填写任意一个旧名称,并且基列名可以与 IColumnsInfo
报告的列名相同。
完成这些之后,我们可以向可更新的代理添加支持,并添加相应的行集属性,这样“信息不足……”错误就消失了。不幸的是,我们还没有真正解决这个问题。
一旦行集支持 IColumnsRowset
,客户端游标引擎就拥有足够的信息以 SQL 形式发出插入、更新和删除请求给行集,这些 SQL 是根据“基表”信息编写的。也就是说,它知道更新中涉及的列和表的真实名称,并且可以编写一个更新语句来处理由联接或数据形状命令引起的行集。不幸的是,这对我们来说意味着我们必须支持 SQL 的更新、插入和删除。
生成的 SQL 作为命令到达我们的提供程序。如果您创建一个表,从其中获取具有客户端游标和乐观锁定的 ADO 记录集,那么当您在数据网格中更改数据并离开单元格时,会在 CConversionProviderCommand::Execute
中设置一个断点。m_strCommandText
的值将是 SQL,大约是
update table set Col1 = ? where Col1 = ? and Col2 = ? and Col3 = ? and Col4 = ?
问号是传递给我们 DBPARAM
访问器的值的占位符。这是因为我们支持 ICommandWithParameters
(这是我们将转换为 ADO 记录集所必需的)。如果我们不支持 ICommandWithParameters
,那么 SQL 将在文本字符串本身中包含值。
update table set Col1 = 'a' where Col1 = '1' and Col2 = '2' and Col3 = '3' and Col4 = '4'
痛苦的 WHERE 子句的原因是我们的数据对象没有任何键列。CCE 不会将书签列用作键列,因此,除非您的数据源有一个有效的唯一键列并且在数据对象GetColumnInformation
方法中的列标志设置为包含 DBCOLUMNFLAGS_ISROWID
,否则 WHERE 子句将被编写成使用所有列来标识需要更改的行。
留给读者的练习……
恐怕我就在这里结束这个问题了。解析 SQL 相对直接,因为语句将只由 CCE 生成,并且应保持一致的形式。您可以通过在提供程序中保留一个映射表来识别命令要操作的行集,并使用映射表中的键作为从对特定行集对象调用 GetColumnsRowset 返回的基表名。如果您的数据源有一个唯一的键,则可以轻松找到要修改的行,如果不是(遗憾的是,CCE 不能在没有其他唯一键的情况下使用书签列……),则需要更费力地查找。一旦您获得了行句柄,您就需要创建一个您传递给您命令的访问器的副本(在行集的上下文中),然后调用 IRowsetChange
中的方法来执行实际工作。
我可能会考虑撰写另一篇文章来涵盖这项最后的收尾工作……
源代码使用 Visual Studio 6.0 SP3 构建。使用了 7 月版的 Platform SDK。如果您没有安装 Platform SDK,您可能会发现编译失败,提示找不到“msado15.h”。您可以通过创建一个包含“adoint.h”的同名文件来解决此问题。