Npgsql 4.0 参数和空值

13

使用Npgsql传递空值的形式如下:

using (NpgsqlCommand cmd = new NpgsqlCommand("insert into foo values (:TEST)", conn))
{
    cmd.Parameters.Add(new NpgsqlParameter("TEST", NpgsqlDbType.Varchar));
    cmd.Parameters[0].Value = DBNull.Value;

    cmd.ExecuteNonQuery();
}

这很好用。

Npgsql 4.0的新文档建议像这样使用强类型声明参数:

using (NpgsqlCommand cmd = new NpgsqlCommand("insert into foo values (:TEST)", conn))
{
    cmd.Parameters.Add(new NpgsqlParameter<string>("TEST", NpgsqlDbType.Varchar));
    cmd.Parameters[0].Value = DBNull.Value;

    cmd.ExecuteNonQuery();
}
当传递DBNull.Value时,会抛出一个一般性的异常:

无法将类型为 'System.DBNull' 的对象强制转换为类型 'System.String'。

使用新的无装箱参数仍然可以正常工作,但是新的语法似乎很有意义,我们想要使用它......但如何解决这种数据类型不匹配的问题?
上面的示例是针对字符串的。我认为这也会影响数字和日期。
2个回答

11
新的通用参数API确实存在问题 - 它应该接受常规的.NET null(而不是DBNull.Value),我已经打开了这个问题来跟踪它,将在4.0.3中修复。
请注意,正如文档注释所说,通用API的整个重点是避免使用类型为objectValue属性。如果您使用通用的NpgsqlParameter<int>但分配Value,则您的int将被装箱,从而使API失去其目的。您应该分配到TypedValue,它的类型是int并且不会装箱。这也是为什么您不能分配DBNull.Value以表示空值(它是不同的.NET类型)。
关于是否应该使用这个新的通用API的一些注意事项:
  • 如果你要写大量的值类型(例如int, DateTime等),这将消除所有装箱分配。这是否会显著取决于应用程序 - 请仔细分析。
  • 通常情况下,当已知类型在编译时,应始终优先使用泛型API而不是非泛型API。这使得编译器可以尽早检查类型正确性,并使您的代码更清晰易懂 - 即使性能不是问题,我们也要使用List<string>而不是ArrayList作为良好编码的一部分。
  • 泛型API的主要(唯一?)缺点是它是特定于Npgsql的,这使得您的代码无法移植到其他数据库驱动程序中(虽然存在问题使其(或类似内容)成为ADO.NET的一部分)。

我完全忽略了TypedValue的部分。感谢您的澄清和所有额外的信息。这太完美了。我希望另一个优点是它会在类型不匹配时发出编译时错误/警告,所以我会找出是否是这种情况。至于不可移植性,对我来说,更好就是更好,所以我宁愿使用它而不是不使用它。同样也可以说PostgreSQL数组--不是很便携,但仍然很棒。说到惊人的事情,NpgSql真是太棒了。感谢您为这个卓越的产品做出的所有贡献。 - Hambone
感谢所有的积极反馈!是的,由于TypedValue是有类型的,它将防止一些不匹配的问题(严格类型总比弱类型更好...) - Shay Rojansky
1
DateTime数据类型中null不是有效值,那该怎么办呢?我只需要使用DateTime吗? - uriDium
这里的文档注释链接已经不存在了。 - Bill Barry

4

我遇到了这个问题,现在我不再遇到异常。

下面是我为Postgres函数声明参数的方法:

string test;
using (NpgsqlCommand cmd = new NpgsqlCommand("insert into foo values (:TEST)", conn))
{
    cmd.Parameters.AddWithValue("TEST", NpgsqlTypes.NpgsqlDbType.Varchar, (object)test?? DBNull.Value);
    cmd.ExecuteNonQuery();
}

"Need"是一个很强的词。在这种情况下,我尝试按照最佳实践指南去做,避免“无用的堆分配”和“对垃圾收集器的过度使用”。http://www.npgsql.org/doc/parameters.html - Hambone
1
唉!我明白你的意思,但在这种情况下,我认为只使用带框参数会更省事且更可靠。例如,日期、时间戳、数字、JSON、XML等等。 - Hambone
@Hambone不要放弃 =) - Igor Cova
1
只是为了明确起见,通用参数 API 确实是推荐的方式 - 它既不需要更多的工作,也不会更加牢固 - 日期/时间戳或任何其他类型都没有使它们更适合传统的非通用 API。但是,请注意,性能优势(节省分配)仅对值类型(例如 int、DateTime)有意义,而不适用于字符串,因为它们已经在堆上分配了。 - Shay Rojansky
1
使用通用参数API需要注意的唯一问题是它是特定于Npgsql的 - 您的代码将在其他数据库上的可移植性较差(至少在此功能被纳入ADO.NET之前)。 - Shay Rojansky
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接