使用 `NpgsqlParameter<T>` 和 `AddWithValue` 与 `NpgsqlDbType` 的区别

Difference Between Using `NpgsqlParameter<T>` and `AddWithValue` with `NpgsqlDbType`

Npgsql documentation 声明使用 NpgsqlParameter<T> 更好,因为它是强类型的,并且不会因装箱值类型导致的无用堆分配而给垃圾收集器带来压力。

我有以下两个命令声明用于特定参数的数据类型:

未使用 NpgsqlParameter<T>:

command.Parameters.AddWithValue("id", NpgsqlTypes.NpgsqlDbType.Integer, 123);

使用NpgsqlParameter<T>:

cmd.Parameters.Add(new NpgsqlParameter<Int32>("id", NpgsqlTypes.NpgsqlDbType.Integer) { TypedValue = 123 });

我的问题是,第一个命令是否等同于第二个命令(不会包含 int 值)或者我应该使用第二个命令?

我认为第一个只是告诉 Npgsql 使用什么数据类型,但仍然会装箱 int

这并不是真正的答案,因为我相信 Harvey 先生已经充分做到了这一点,但它比我可以发表评论的时间要长,而且不会有格式……所以提前道歉。

首先,请参阅 Npgsql 的一位作者关于何时应使用泛型 API 的反馈:

此外,我在这个 post 中没有看到它,但我记得他的评论也指出新 API 的缺点之一是它不可移植到其他 ADO.net 适配器,这意味着如果您将数据源更改为 Oracle,预计这将不起作用。

现在谈谈我对热门体育的看法...我已经看到、理解并同意不使用 AddWithValue 的理由。也就是说,我将是第一个承认我使用它的人。原因是它通常有效,而且我认为方法名称对于它正在完成的事情是非常透明的。

我严格避免的两种情况是:

  • 声明一次,分配多次,就像在您进行多次插入、更新(或更新插入)的事务中一样
  • 日期。由于 PostreSQL 有日期和时间戳,但 .NET 只有 System.Datetime,AddWithValue 似乎假设您的意思是 System.DateTime -> 时间戳,这将导致您的程序呕吐。在这种情况下,AddWithValue 为您节省了很少的时间,因为您需要将数据类型重新声明为日期

不过,它确实适用于数组数据类型,这非常棒。

所以,你可以这样做:

cmd.Parameters.Add(new NpgsqlParameter("FOO", NpgsqlDbType.Array | NpgsqlDbType.Varchar));
cmd.Parameters[0].Value = myArray;

或者你可以这样做:

cmd.Parameters.AddWithValue("FOO", myArray);

它工作得很好......我真的很喜欢 PostgreSQL 和 NpgSql。

NpgsqlParameter 优于 AddWithValue 的主要优点是避免装箱,因为 AddWithValue 接受一个对象。这意味着任何时候您将值类型 (int, double) 传递给 AddWithValue,都会招致不必要的堆分配。

至于其余部分...根据上面发布的链接,我不知道与类型推断和性能相关的任何其他优势。 NpgsqlParameter 接受强类型的 .NET 类型,但 Npgsql 仍必须从中推断出 PostgreSQL 类型。例如,.NET string 可以映射到 PostgreSQL text,但也可以 varcharjsonb。事实上,无论 .NET 类型是使用 NpgsqlParameter 一般指定的,还是仅通过查看传递给 AddWithValue 的对象的类型,内部发生的类型推断都是相同的。如果您想避免推断,则必须指定一个 NpgsqlDbType - 包括 NpgsqlParameter

另请注意,我不知道与错误推理相关的重要或常见 性能 问题(如某些 SQL 服务器链接中所暗示)。在大多数情况下,查询将简单地失败,因为推断的类型在某种程度上不兼容 - 但它很少 运行 缓慢。

在仔细考虑了我们从社区收到的意见后,我们决定使用 NpgsqlParameter<T> 和明确的 NpgsqlDbType

虽然我们同意这两个选项确实很难注意到性能影响,但声明您正在传递的内容以及您希望将其转换为的内容的明确性使我们确信使用稍微更冗长的选项.

非常感谢所有帮助过的人!