如何在C#中向PostgreSQL函数传递自定义类型数组
问题背景
我在PostgreSQL中定义了如下自定义复合类型及使用该类型的函数:
create type my_type as ( id bigint, value character varying(100) ); create or replace function my_function ( my_array my_type[]) returns table (id bigint) language 'plpgsql' as $BODY$ begin return query select id from my_table as t where t.id in ( select ar.id from unnest(my_array) as ar ); end; $BODY$;
该函数在PostgreSQL中的调用方式如下:
select * from my_function(array[(1, 't')::my_type, (3, 'b')::my_type]);
我使用.NET Core 8.0和Npgsql 8.0.2进行测试,定义了对应的POCO类:
public class MyType { public int Id {get; set;} public string Value {get; set;} }
尝试通过以下代码调用函数时:
var dsBuilder = new NpgsqlDataSourceBuilder("my-connection-string"); dsBuilder.MapComposite<MyType>("my_type"); using var ds = dsBuilder.Build(); using var conn = ds.OpenConnection(); var cmd = new NpgsqlCommand("select * from my_function(@arr)", conn); cmd.Parameters.AddWithValue( "arr", new MyType[] { new MyType(){ Id = 1, Value = "t" }, new MyType(){ Id = 3, Value = "b" }, } );
运行时报错:Writing values of 'Program+MyType[]' is not supported for parameters having no NpgsqlDbType or DataTypeName,尝试传递IEnumerable<MyType>和List<MyType>类型参数也无效。想知道如何用NpgsqlDataSource在C#中正确调用该函数,是否必须改用低效的单个调用或JSON参数?
解决方法
你需要明确指定参数的PostgreSQL数据类型,因为Npgsql无法自动推断复合类型数组的类型信息,有两种可行方式:
方式一:指定参数的DataTypeName
在添加参数时,显式指定DataTypeName为my_type[](注意是数组类型名):
cmd.Parameters.AddWithValue( "arr", NpgsqlTypes.NpgsqlDbType.Array | NpgsqlTypes.NpgsqlDbType.Composite, new MyType[] { new MyType(){ Id = 1, Value = "t" }, new MyType(){ Id = 3, Value = "b" }, } );
或者单独设置参数的DataTypeName属性:
var param = cmd.Parameters.AddWithValue( "arr", new MyType[] { new MyType(){ Id = 1, Value = "t" }, new MyType(){ Id = 3, Value = "b" }, } ); param.DataTypeName = "my_type[]";
方式二:使用NpgsqlParameter构造函数指定类型
通过构造函数直接声明参数的数据库类型:
var param = new NpgsqlParameter("arr", NpgsqlDbType.Array | NpgsqlDbType.Composite) { Value = new MyType[] { new MyType(){ Id = 1, Value = "t" }, new MyType(){ Id = 3, Value = "b" }, }, DataTypeName = "my_type[]" }; cmd.Parameters.Add(param);
这样Npgsql就能正确识别参数类型为自定义复合类型的数组,从而完成映射和调用。不需要改用单个调用或JSON参数,这种方式是原生支持的高效方案。
内容的提问来源于stack exchange,提问作者Bagus Tesa
相关产品推荐
相关产品推荐

