使用 OLE DB 插入 BLOB
我正在开发一个使用 OLE DB 和 SQL Server Native Client 访问 SQL Server DB 的应用程序。到目前为止,我只处理过相当简单的 SQL。为此,我一直在获取 ICommandText
并使用 SetCommandText
。我现在想将一个大对象插入数据库。我看到 ICommandStream
存在,但似乎使用它需要我添加一个实现 IStream
的类,并适当地引用我的 BLOB(转义撇号等) 。当然有更简单的方法吗?
旁注:OLE DB 不是我的选择,现阶段我无法更改它。因此,更简单的方法“使用更高级别的东西”不可用。
I'm working on an app which is using OLE DB and SQL Server Native Client to access a SQL Server DB. To date, I've only been dealing with fairly simple SQL. For this, I've been obtaining an ICommandText
and using SetCommandText
. I now want to insert a large object into the database. I see that ICommandStream
exists, but it seems like using this would require me to add a class that implements IStream
and also to quote my BLOB appropriately (escaping apostrophes, etc.). Surely there's an easier way?
Side note: OLE DB wasn't my choice and I can't change it at this stage. So the easier way "use something higher-level" isn't available.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Blob 只是二进制数据,因此您需要使用某种形式的字节数组。
A blob is just binary data, so you'll need to use some form of byte array.
事实证明,有一个 Microsoft SQLNCli 团队博客上的回答。
为了扩展这一点,这是我最终使用的代码。首先,您需要一个可供 SQL Server Native Client 读取的 ISequentialStream。我的数据在内存中,所以我可以用指向我的 BLOB 的指针来构造它,但是从其他地方获取数据很简单。它不是合同的一部分,但了解读取似乎以 1024 字节块的形式发生可能很有用。这是我的流类:
这个的实现很简单:
使用
ICommandText
,然后您可以在表上执行SELECT
。您实际上并不打算使用它检索任何数据,它只是获取IRowsetChange
的一种方法。我为此有一个额外的 ExecuteCommand 方法。 pSQL 中传递的 SQL(类似于)SELECT x,y,z FROM TableWithBlob
。FAIL
是一个自定义宏,记录问题并返回。我现在有一个针对相关表的 IRowset 和 IRowsetChange。然后,您可以像平常一样构造一个
DBBINDING
。我忽略了这一点 - 它与问题并不真正相关。相关位是:当随后填充匹配的数据内存块时,您可以执行以下操作(对丑陋的转换感到抱歉):
使用您的
IRowsetChange
获取一个IAccessor
并绑定它:最后,您可以插入行:
SQL Server Native Client 将从您的流中读取并插入行。现在跳圈已经完成了。删除了ReleaseAccessor、清理等。
It turns out, there's an answer on the Microsoft SQLNCli team blog.
To expand on this, here's the code I ended up using. First, you need an ISequentialStream for SQL Server Native Client to be reading from. I have my data in memory, so I could just construct this with a pointer to my BLOB, but it's trivial to go and get the data from elsewhere. It's not part of the contract, but it's perhaps useful to know that the reads seem to happen in 1024-byte chunks. Here's my stream class:
The implementation of this is trivial:
Using an
ICommandText
, you can then execute aSELECT
on the table. You're not actually going to retrieve any data using this, it's just a way of getting anIRowsetChange
. I have an extra ExecuteCommand method for this. The SQL passed in pSQL is (similar to)SELECT x,y,z FROM TableWithBlob
.FAIL
is a custom macro that records the problem and returns.I now have an IRowset and an IRowsetChange for the table in question. You then construct a
DBBINDING
as you normally would. I'm eliding this - it's not really relevant to the question. The relevant bit is:When subsequently filling in the matching data memory block, you can then do this (sorry for the ugly casts):
Get yourself an
IAccessor
using yourIRowsetChange
and bind it:Finally, you can insert your row:
SQL Server Native Client will read from your stream and insert the row. The hoop-jumping is now done.
ReleaseAccessor
, cleanup, etc. elided.