传递多维 Npgsql 参数?
passing multidimensional NpgsqlParameters?
我在 asp.net 核心项目中有以下有效的 C# 代码:
... /* words is of type List<string> */
var query = $"SELECT * FROM a_table WHERE word = ANY(@words) AND token = 'some string'";
using (var connection = new NpgsqlConnection(ConnectionString))
{
connection.Open();
var cmd = new NpgsqlCommand(query, connection);
cmd.Parameters.Add("@words", NpgsqlDbType.Array | NpgsqlDbType.Text).Value = words;
var reader = cmd.ExecuteReader();
while (reader.Read())
{
...
这行得通。当令牌精确时,我正在检查单词的结果是否被缓存 something else
.
当 words
中每个单词的 token
不同时,问题就开始了。我想检查数据库中是否有任何匹配项。当我直接在数据库中 运行 时,以下 SQL 有效:
SELECT * FROM a_table WHERE (word, token) IN (('able', 'something else'), ('pizza', 'something else entirely'))
我现在想像这样在 c# 中使用它:
... /* words was a List<> of a custom type with two string auto properties, but I changed it to List<List<string>> when that didn't work. Didn't help much. */
var query = $"SELECT * FROM a_table WHERE (word, token) IN @words";
using (var connection = new NpgsqlConnection(ConnectionString))
{
connection.Open();
var cmd = new NpgsqlCommand(query, connection);
cmd.Parameters.Add("@words", NpgsqlDbType.Array | NpgsqlDbType.Array | NpgsqlDbType.Text).Value = words;
var reader = cmd.ExecuteReader();
while (reader.Read())
{
...
但我猜 npgsql 无法处理 - 没有类型是字符串数组的数组?
Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HLFDVA1DP743", Request id "0HLFDVA1DP743:00000002": An unhandled exception was thrown by the application.
System.Exception: While trying to write an array, one of its elements failed validation. You may be trying to mix types in a non-generic IList, or to write a jagged array. ---> System.InvalidCastException: Can't write CLR type System.Collections.Generic.List`1[System.String] with handler type TextHandler
at lambda_method(Closure , NpgsqlTypeHandler , Object , NpgsqlLengthCache& , NpgsqlParameter )
...
有没有正确的方法传入多维数组?还是必须自己搭建,失去注入保护?我认为参数应该让整个事情变得更简单!请注意,我也不知道单词列表中会有多少项。
But I guess npgsql can't handle that - there's no type that's an array of arrays of strings?
PostgreSQL 支持多维数组 (int[,]
),但不支持交错数组 (int[][]
)。
Is there a proper way of passing in a multidimensional array?
是的,这是一个 example:
[Test, Description("Roundtrips a two-dimensional array of ints")]
public void TwoDimensionalInts()
{
using (var conn = OpenConnection())
using (var cmd = new NpgsqlCommand("SELECT @p1, @p2", conn))
{
var expected = new[,] { { 1, 2, 3 }, { 7, 8, 9 } };
var p1 = new NpgsqlParameter("p1", NpgsqlDbType.Array | NpgsqlDbType.Integer);
var p2 = new NpgsqlParameter { ParameterName = "p2", Value = expected };
cmd.Parameters.Add(p1);
cmd.Parameters.Add(p2);
p1.Value = expected;
var reader = cmd.ExecuteReader();
reader.Read();
Assert.That(reader.GetValue(0), Is.EqualTo(expected));
Assert.That(reader.GetProviderSpecificValue(0), Is.EqualTo(expected));
Assert.That(reader.GetFieldValue<int[,]>(0), Is.EqualTo(expected));
}
}
The following SQL works when I run it in the database directly:
SELECT *
FROM a_table
WHERE (word, token) IN (('able', 'something else'), ('pizza', 'something else entirely'))
确实有效...但它不涉及任何数组。您正在行集合中搜索一行:
postgres=# SELECT ('able', 'something else');
row
-------------------------
(able,"something else")
(1 row)
postgres=# SELECT (0, 1) IN (u.t) FROM (SELECT unnest(ARRAY[(0, 1), (2, 3)]) AS t) AS u;
?column?
----------
t
(1 row)
我在 asp.net 核心项目中有以下有效的 C# 代码:
... /* words is of type List<string> */
var query = $"SELECT * FROM a_table WHERE word = ANY(@words) AND token = 'some string'";
using (var connection = new NpgsqlConnection(ConnectionString))
{
connection.Open();
var cmd = new NpgsqlCommand(query, connection);
cmd.Parameters.Add("@words", NpgsqlDbType.Array | NpgsqlDbType.Text).Value = words;
var reader = cmd.ExecuteReader();
while (reader.Read())
{
...
这行得通。当令牌精确时,我正在检查单词的结果是否被缓存 something else
.
当 words
中每个单词的 token
不同时,问题就开始了。我想检查数据库中是否有任何匹配项。当我直接在数据库中 运行 时,以下 SQL 有效:
SELECT * FROM a_table WHERE (word, token) IN (('able', 'something else'), ('pizza', 'something else entirely'))
我现在想像这样在 c# 中使用它:
... /* words was a List<> of a custom type with two string auto properties, but I changed it to List<List<string>> when that didn't work. Didn't help much. */
var query = $"SELECT * FROM a_table WHERE (word, token) IN @words";
using (var connection = new NpgsqlConnection(ConnectionString))
{
connection.Open();
var cmd = new NpgsqlCommand(query, connection);
cmd.Parameters.Add("@words", NpgsqlDbType.Array | NpgsqlDbType.Array | NpgsqlDbType.Text).Value = words;
var reader = cmd.ExecuteReader();
while (reader.Read())
{
...
但我猜 npgsql 无法处理 - 没有类型是字符串数组的数组?
Microsoft.AspNetCore.Server.Kestrel[13] Connection id "0HLFDVA1DP743", Request id "0HLFDVA1DP743:00000002": An unhandled exception was thrown by the application. System.Exception: While trying to write an array, one of its elements failed validation. You may be trying to mix types in a non-generic IList, or to write a jagged array. ---> System.InvalidCastException: Can't write CLR type System.Collections.Generic.List`1[System.String] with handler type TextHandler at lambda_method(Closure , NpgsqlTypeHandler , Object , NpgsqlLengthCache& , NpgsqlParameter ) ...
有没有正确的方法传入多维数组?还是必须自己搭建,失去注入保护?我认为参数应该让整个事情变得更简单!请注意,我也不知道单词列表中会有多少项。
But I guess npgsql can't handle that - there's no type that's an array of arrays of strings?
PostgreSQL 支持多维数组 (int[,]
),但不支持交错数组 (int[][]
)。
Is there a proper way of passing in a multidimensional array?
是的,这是一个 example:
[Test, Description("Roundtrips a two-dimensional array of ints")]
public void TwoDimensionalInts()
{
using (var conn = OpenConnection())
using (var cmd = new NpgsqlCommand("SELECT @p1, @p2", conn))
{
var expected = new[,] { { 1, 2, 3 }, { 7, 8, 9 } };
var p1 = new NpgsqlParameter("p1", NpgsqlDbType.Array | NpgsqlDbType.Integer);
var p2 = new NpgsqlParameter { ParameterName = "p2", Value = expected };
cmd.Parameters.Add(p1);
cmd.Parameters.Add(p2);
p1.Value = expected;
var reader = cmd.ExecuteReader();
reader.Read();
Assert.That(reader.GetValue(0), Is.EqualTo(expected));
Assert.That(reader.GetProviderSpecificValue(0), Is.EqualTo(expected));
Assert.That(reader.GetFieldValue<int[,]>(0), Is.EqualTo(expected));
}
}
The following SQL works when I run it in the database directly:
SELECT * FROM a_table WHERE (word, token) IN (('able', 'something else'), ('pizza', 'something else entirely'))
确实有效...但它不涉及任何数组。您正在行集合中搜索一行:
postgres=# SELECT ('able', 'something else');
row
-------------------------
(able,"something else")
(1 row)
postgres=# SELECT (0, 1) IN (u.t) FROM (SELECT unnest(ARRAY[(0, 1), (2, 3)]) AS t) AS u;
?column?
----------
t
(1 row)