如何使用 Dapper 反序列化数组

How to deserialize array using Dapper

我有一个模型有一个 HashSet<int> 成员。由于我无法让 Dapper 自动从数组创建集合,我想我会使用多映射查询并将数组作为单独的列获取,拆分它并在 lambda 中创建集合。明确一点,我想反序列化整个模型,而不仅仅是集合的位。

我的第一次多映射尝试也失败了,所以我决定尝试更简单的方法,获取一个数组并将其反序列化为List<int>int[]。这就是我被困的地方。

我正在使用 PostgreSQL 12 数据库。

代码片段如下

var query = "SELECT ARRAY[1, 2, 3];";

var ints1 = await _conn.QueryAsync<List<int>>(query); // This returns an empty array
var ints2 = await _conn.QueryAsync<int[]>(query); // System.ArgumentException: Invalid type owner for DynamicMethod.

我不太确定我做错了什么,Google 似乎没有什么帮助,我只发现有关在查询中使用列表的问题。

编辑:好的,我通过将数组转换为 JSON 使其工作,但我仍然觉得这个解决方案很丑陋。有没有办法避免创建 JSONs?

答案在评论中,但是 TL;DR 这做不到。数组必须转换为字符串,然后反序列化为列表。

我是在回答这个问题而不是关闭它,因为我相信如果您主要使用 Postgres 并且可能期望数组在其他 RDMS 中也是一个东西,那么这是一个有效的问题。

不要相信你听到的一切,虽然上面说这是不可能的,但实际上很容易实现。

确实,下面的查询会给您一个错误:(DynamicMethod 的类型所有者无效):

var arrayOfThreeElements =  
        (await _conn.QueryAsync<int[]>("SELECT ARRAY[1, 2, 3]"))                  
              .FirstOrDefault();

您需要做的是告诉 dapper 如何使用小型 TypeHandler 处理此问题:

public class GenericArrayHandler<T> : SqlMapper.TypeHandler<T[]>
{
    public override void SetValue(IDbDataParameter parameter, T[] value)
    {
        parameter.Value = value;
    }

    public override T[] Parse(object value) => (T[]) value;
}

Parse 方法在这里很重要。

然后您只需在添加所有其他类型处理程序的位置添加此处理程序 - 即在您的应用程序或网站的初始化代码中,如下所示:

SqlMapper.AddTypeHandler(new GenericArrayHandler<int>());

现在查询有效,returns 整数数组中的 3 个元素 1,2 和 3。