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