You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Dapper+Npgsql 7.0+调用带自定义类型列表参数的PostgreSQL存储过程

解决Npgsql 7.0 + Dapper 调用PostgreSQL存储过程并传递复合类型列表的问题

1. 核心错误解决:正确注册复合类型到NpgsqlDataSource

你遇到的NotSupportedException是因为复合类型未与NpgsqlDataSource完成绑定。Npgsql 7.0废弃了全局类型映射,必须通过NpgsqlDataSourceBuilder在数据源层面注册复合类型。

操作步骤:

  • 确保CLR类的属性名与PostgreSQL复合类型的字段名一致(PostgreSQL默认小写,Npgsql会自动匹配PascalCase的CLR属性)
  • 通过NpgsqlDataSourceBuilder的MapComposite方法,将CLR类型映射到PostgreSQL的复合类型名称
  • 从构建好的数据源获取连接,供Dapper使用

2. 是否可以避免CALL写法?

可以。Dapper支持通过CommandType.StoredProcedure直接调用存储过程,无需手动编写CALL语句,只需保证参数名与存储过程参数完全匹配。

完整代码示例

第一步:PostgreSQL端准备

先创建复合类型和目标存储过程:

-- 创建复合类型
CREATE TYPE customer_type AS (
    id INT,
    name VARCHAR(100),
    email VARCHAR(100)
);

-- 创建接收复合类型列表的存储过程
CREATE OR REPLACE PROCEDURE insert_customer_list(cust_list customer_type[])
LANGUAGE plpgsql
AS $$
BEGIN
    INSERT INTO customers (id, name, email)
    SELECT id, name, email FROM unnest(cust_list);
END;
$$;

第二步:.NET端代码

定义CLR复合类型

public class CustomerType
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
}

配置数据源并结合Dapper调用

using Dapper;
using Npgsql;

// 1. 构建数据源并注册复合类型
var dataSourceBuilder = new NpgsqlDataSourceBuilder("Host=localhost;Database=your_db;Username=postgres;Password=your_pwd");
// 第二个参数是PostgreSQL中定义的复合类型名称(严格匹配)
dataSourceBuilder.MapComposite<CustomerType>("customer_type");
var dataSource = dataSourceBuilder.Build();

// 2. 准备要传递的复合类型列表
var customers = new List<CustomerType>
{
    new CustomerType { Id = 1, Name = "Alice", Email = "alice@example.com" },
    new CustomerType { Id = 2, Name = "Bob", Email = "bob@example.com" }
};

// 3. 用Dapper调用存储过程(两种方式可选)
// 方式一:推荐,使用CommandType.StoredProcedure无需写CALL
using var conn = dataSource.OpenConnection();
await conn.ExecuteAsync(
    "insert_customer_list", // 存储过程名称
    new { cust_list = customers }, // 参数名与存储过程参数完全匹配
    commandType: CommandType.StoredProcedure
);

// 方式二:兼容旧写法,手动写CALL
// await conn.ExecuteAsync("CALL insert_customer_list(@cust_list)", new { cust_list = customers });

关键注意事项

  • 复合类型名称必须严格匹配:MapComposite的第二个参数要和PostgreSQL中定义的类型名完全一致(比如customer_type)
  • 必须使用从NpgsqlDataSource获取的连接,类型映射是绑定在数据源实例上的,而非全局生效
  • 如果涉及嵌套复合类型,需通过dataSourceBuilder.MapComposite逐一注册相关类型

内容的提问来源于stack exchange,提问作者Swaroop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 00:00:20