传递多维 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)