Informix (C#):如何正确设置/取消设置 blob 字段?
IBM Informix SDK:
语句:Update mytable set myblobcolumn = ? where myid = 1;
using (IfxConnection conn = GetIfxConnection())
using (IfxCommand cmd = new IfxCommand(updateSql, conn))
{
var param = new IfxParameter("myblobcolumn", IfxType.Blob) { IsNullable = true };
cmd.Parameters.Add(param).Value = DBNull.Value
cmd.ExecuteNonQuery(); //ERROR [HY000] [Informix .NET provider][Informix]Illegal attempt to use Text/Byte host variable.
}
如果我用另一个 IfxBlob
对象更新它,它工作正常,但如果我用 DBNull.Value
更新它,我会收到错误。有人知道如何使用参数化更新“取消设置”blob 列吗?
更新:
好的,我做了一些研究并减少了一些内容。
首先,我发现,如果我在生成参数时显式声明 IfxType
,则 .NET 驱动程序在从 null 值来回切换时,将无法转换 DBNull.Value 甚至 Byte[] 数组。数据库并在数据库中有一个实际的 IfxBlob。基本上:
- 如果该列包含一个值,并且我希望在其中存储 null,那么我必须按如下方式对参数进行类型转换:
UPDATE mytable SET myblobcolumn = ?::byte WHERE myid = 1;
。这使我能够毫无错误地存储DBNull.Value
的值。 - 如果该列包含空值并且我希望在其中存储实际值,那么我必须按如下方式对参数进行类型转换:
UPDATE mytable SET myblobcolumn = ?::blob WHERE myid = 1;
。这允许我存储 IfxBlob 值。
现在,为了避免所有这些,我将参数初始化减少为仅设置 ParameterName 属性: var param = new IfxParameter { ParameterName = "myblobcolumn" }
(甚至这只是为了能够引用它来自收藏,仅此而已)。这让我可以保留我的声明,而不必对我的参数进行类型转换。
所以...我留下以下内容:
语句: UPDATE mytable SET myblobcolumn = ? where myid = 1;
using (IfxConnection conn = GetIfxConnection())
using (IfxCommand cmd = new IfxCommand(updateSql, conn))
{
var param = new IfxParameter { ParameterName = "myblob" }
cmd.Parameters.Add(param);
var value = GetSomeValue();
if (value is Byte[])
cmd.Paremeters["myblob"].Value = GetIfxBlob(value);
else
cmd.Parameters["myblob"].Value = DBNull.Value;
//...
}
这工作得很好,除了我认为我在 Informix .NET 驱动程序 (3.50.xC7) 中发现了一个类似于 这个。基本上,提供的链接指出发现了一个错误,该错误不允许 .NET 驱动程序在执行插入时正确使用 byte[] 数组来创建 blob。这个问题已经得到解决,因为我在执行 INSERT 语句时实际上可以执行 cmd.Parameters["myblob"].Value = new Byte[] { 0x1, 0x2 };
。但是,当使用 byte[] 数组作为 UPDATE 语句时,驱动程序仍然会给出异常。因此,我必须实际创建 IfxBlob 实例并使用它们而不是实际的 byte[] 数组。
如果这不是驱动程序中的错误,那么这个问题需要保持开放状态,以了解设置/取消设置 blob 字段的正确方法是使用 byte[] 数组进行更新。
IBM Informix SDK:
Statement: Update mytable set myblobcolumn = ? where myid = 1;
using (IfxConnection conn = GetIfxConnection())
using (IfxCommand cmd = new IfxCommand(updateSql, conn))
{
var param = new IfxParameter("myblobcolumn", IfxType.Blob) { IsNullable = true };
cmd.Parameters.Add(param).Value = DBNull.Value
cmd.ExecuteNonQuery(); //ERROR [HY000] [Informix .NET provider][Informix]Illegal attempt to use Text/Byte host variable.
}
If I update it with another IfxBlob
object it works fine, but if I update it with DBNull.Value
I get an error. Anyone know how to "unset" the blob column using a parameterized update?
Update:
Ok, I did some research and have reduced things down a bit.
Firstly, I found that if I explicitly declare the IfxType
when generating the parameter, the .NET driver has trouble converting DBNull.Value or even a Byte[] array when switching back and forth from a null value in the database and having an actual IfxBlob in the database. Basically:
- If the column contains a value and I wish to store null in it instead then I must typecast my parameter as follows:
UPDATE mytable SET myblobcolumn = ?::byte WHERE myid = 1;
. This allows me to store the value ofDBNull.Value
without any errors. - If the column contains a null value and I wish to store an actual value in it instead then I must typecast my parameter as follows:
UPDATE mytable SET myblobcolumn = ?::blob WHERE myid = 1;
. This allows me to store the IfxBlob value.
Now, to avoid all that I reduced down the Parameter initialization to only setting the ParameterName property: var param = new IfxParameter { ParameterName = "myblobcolumn" }
(and even that is just to be able to reference it from the collection, nothing more). This let me keep my statement without having to typecast my parameter.
so... I'm left with the following:
Statement: UPDATE mytable SET myblobcolumn = ? where myid = 1;
using (IfxConnection conn = GetIfxConnection())
using (IfxCommand cmd = new IfxCommand(updateSql, conn))
{
var param = new IfxParameter { ParameterName = "myblob" }
cmd.Parameters.Add(param);
var value = GetSomeValue();
if (value is Byte[])
cmd.Paremeters["myblob"].Value = GetIfxBlob(value);
else
cmd.Parameters["myblob"].Value = DBNull.Value;
//...
}
This works fine, except I think I discovered a bug in the Informix .NET Driver (3.50.xC7) similar to the this one. Basically, the link provided states that there was a bug discovered which did not allow the .NET driver to properly use a byte[] array to create a blob when doing an insert. That has been fixed in that I can literally do cmd.Parameters["myblob"].Value = new Byte[] { 0x1, 0x2 };
when doing an INSERT statement. However, the driver still gives an exception when using the byte[] array for an UPDATE statement. Hence, I had to actually create IfxBlob instances and use those instead of the actual byte[] array.
If this isn't a bug in the driver then this question needs to stay open to see what the proper way to set/unset a blob field is using a byte[] array for UPDATES.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我想,既然没有人说我所经历的不是一个错误,我将发布我的发现作为答案:
对于 Informix .NET 提供程序(版本:3.5.xC7),请勿显式设置生成
IfxParameter
(或DbParameter
)时的IfxType
或DbType
。相反,只需生成参数并允许 Informix .NET 提供程序为您映射正确的类型。这使您不必担心参数的类型转换(即避免“?::blob”和“?::byte”)。由于错误(版本:3.5.xC7),将 byte[] 数组插入 Blob 字段可以正常工作,但使用 byte[] 数组更新该 Blob 字段将导致 609 错误。相反,必须创建一个
IfxBlob
并将其设置为值。这在执行插入时也有效。I figured that since no one stated that what I experienced isn't a bug, I'll post my findings as an answer:
For the Informix .NET provider (ver: 3.5.xC7), do NOT, explicitly set the
IfxType
orDbType
when generating anIfxParameter
(orDbParameter
). Instead, just generate the parameter and allow the Informix .NET provider to map the correct types for you. This allows you to not have to worry about typecasting your parameters (i.e. avoid, "?::blob" and "?::byte").Due to a bug (ver: 3.5.xC7), inserting a byte[] array into a Blob field works fine, but updating that Blob field using a byte[] array will result in a 609 error. Instead, an
IfxBlob
will have to be created and set as the value. This also works when doing inserts.