Npgsql 4.0 参数和空值

Npgsql 4.0 Parameters and Null Values

使用 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时,抛出一般异常:

Unable to cast object of type 'System.DBNull' to type 'System.String'.

一切仍然适用于新的无装箱参数,但新语法似乎很有意义,我们想使用它...但是如何解决此数据类型断开连接?

上面的例子是一个字符串。我认为这也会影响数字和日期。

我遇到过这个问题,现在没有遇到异常

这里是我如何为 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();
}

新的通用参数 API 确实有问题 - 它应该接受常规 .NET null(而不是 DBNull.Value),我已经打开 this issue为了跟踪这个问题,它将在 4.0.3 中修复。

请注意,正如 the documentation note 所说,泛型 API 的全部意义在于避免使用类型为 [=13= 的 Value 属性 ].如果您使用泛型 NpgsqlParameter<int> 但分配 Value,您的 int 将被装箱,从而违背 API 的目的。您应该分配给 TypedValue,它的类型是 int,不会装箱。这也是为什么不能分配 DBNull.Value 来指示空值(它是不同的 .NET 类型)的原因。

关于是否应该使用这个新的泛型 API 的一些注意事项:

  • 如果您正在编写大量值类型(例如 intDateTime...),这将删除所有装箱分配。这是否重要取决于您的应用程序 - 仔细分析。
  • 泛型 API 一般而言,当类型在编译时已知时,应始终优先于非泛型。这允许编译器及早检查类型正确性并使您的代码更清晰 - 我们使用 List<string> 而不是 ArrayList 作为良好编码的问题,即使性能不是问题
  • 泛型 API 的主要(唯一?)缺点是它是特定于 Npgsql 的,这使得您的代码无法移植到其他数据库驱动程序(尽管 an issue exists 用于制作这个(或其他东西)相似)ADO.NET)的一部分。