如何用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
相关产品推荐
相关产品推荐

