Npgsql C# - 将参数作为复合类型数组传递到存储过程中
Npgsql C# - pass parameters as array of composite type into stored procedure
也许这个主题与这个 Array of composite type as stored procedure input passed by C# Npgsql 重复。但那是 2017 年的旧版本,一些 API、属性已被弃用。
目前,我正在尝试将一组复合类型传递给存储过程。我确实映射了一个全局复合类型。但是抛出了异常 Can't write CLR type Web.API.Models.UdtSpParameter[] with handler type MappedCompositeHandler`1
我尝试 google 似乎没有找到解决该问题的任何结果。下面下面是我创建、映射、调用命令存储过程。
Postgresql
/* Create composite type */
CREATE TYPE udt_sp_parameter AS (
field VARCHAR(50),
value VARCHAR
);
/* Create stored procedure */
CREATE OR REPLACE PROCEDURE stored_example(
parameters udt_sp_parameter[])
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
_refCursor CURSOR FOR SELECT field, value FROM UNNEST(parameters::udt_sp_parameter[]);
_record udt_sp_parameter;
BEGIN
OPEN _refCursor;
LOOP
FETCH _refCursor INTO _record;
IF NOT FOUND THEN
EXIT;
END IF;
RAISE NOTICE 'Field: %', _record.field;
RAISE NOTICE 'Value: %', _record.value IS NULL;
END LOOP;
CLOSE _refCursor;
END;
$BODY$;
并且我尝试用plpgsql语言调用存储并且工作正常。
DO
$$
DECLARE
parameters udtt_input_param[] := ARRAY[
ROW('YED','Yeti')
,ROW('INTELLIGENT','NOOB')
,ROW('ZXC',NULL)
,ROW('CXX','1')];
BEGIN
CALL stored_example(parameters);
END
$$
LANGUAGE plpgsql
C# Npgsql (nuget Npgsql 4.1.4)
// mapping global type on Startup.cs
NpgsqlConnection.GlobalTypeMapper.MapComposite<UdtSpParameter>("udt_sp_parameter");
// class model UdtSpParameter
public class UdtSpParameter
{
[PgName("field")]
public string Field { get; set; }
[PgName("value")]
public string Value { get; set; }
public UdtSpParameter() { }
}
// call stored procedure at data access layer for example StudentDAL.cs
public IEnumerable<T> CallStoredResultSet<T>(UdtSpParameter[] inputParameters ) where T : class
{
var conn = _GetOpenConnection();
var tran = _BeginTransaction(conn);
NpgsqlCommand command = new NpgsqlCommand("stored_example", conn);
command.CommandType = CommandType.StoredProcedure;
var cmdParam = command.CreateParameter();
cmdParam.ParameterName = "parameters";
cmdParam.DbType = DbType.Object;
cmdParam.Value = inputParameters;
cmdParam.DataTypeName = "udt_sp_parameter";
command.Parameters.Add(cmdParam);
// throw exception here
// Can't write CLR type Web.API.Models.UdtSpParameter[] with handler type MappedCompositeHandler`1
NpgsqlDataReader dr = command.ExecuteReader();
var result = new List<T>();
while (dr.Read())
{
Console.WriteLine(dr[0].ToString(), dr[1].ToString());
}
_CommitTransaction(tran);
_CloseConnection(conn);
return result;
}
如果我做错了什么,请找些东西告诉我改正。提前致谢。
您出现此错误是因为您为参数指定了类型名称,该参数是复合类型而不是复合数组。因此,您应该将 udt_sp_parameter[]
指定为 DataTypeName
的值,而不是 udt_sp_parameter
:
var cmdParam = command.CreateParameter();
cmdParam.ParameterName = "parameters";
cmdParam.Value = inputParameters;
cmdParam.DataTypeName = "udt_sp_parameter[]";
由于您的类型已注册并且驱动程序已经知道其 PostgreSQL 名称,因此无需在参数设置期间指定它。请随意删除上面代码的最后一行:
var cmdParam = command.CreateParameter();
cmdParam.ParameterName = "parameters";
cmdParam.Value = inputParameters;
在大多数情况下,驱动程序足够智能,可以自动检测类型,但是当有歧义时,应该指定它。例如,您有一个应作为 JSON 传递的字符串,或者应将 CLR 类型序列化为 JSON。在其他情况下,只依赖于驱动程序的内部结构并让他完成他的工作。
Npgsql的官方文档说:
The only way to call a stored procedure is to write your own CALL
my_proc(...) command, without setting CommandBehavior.StoredProcedure.
在您的特定情况下,您应该像这样修改代码:
NpgsqlCommand command = new NpgsqlCommand("call stored_example(:parameters)", conn);
// comment this line command.CommandType = CommandType.StoredProcedure;
希望对兄弟有帮助
也许这个主题与这个 Array of composite type as stored procedure input passed by C# Npgsql 重复。但那是 2017 年的旧版本,一些 API、属性已被弃用。
目前,我正在尝试将一组复合类型传递给存储过程。我确实映射了一个全局复合类型。但是抛出了异常 Can't write CLR type Web.API.Models.UdtSpParameter[] with handler type MappedCompositeHandler`1
我尝试 google 似乎没有找到解决该问题的任何结果。下面下面是我创建、映射、调用命令存储过程。
Postgresql
/* Create composite type */
CREATE TYPE udt_sp_parameter AS (
field VARCHAR(50),
value VARCHAR
);
/* Create stored procedure */
CREATE OR REPLACE PROCEDURE stored_example(
parameters udt_sp_parameter[])
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
_refCursor CURSOR FOR SELECT field, value FROM UNNEST(parameters::udt_sp_parameter[]);
_record udt_sp_parameter;
BEGIN
OPEN _refCursor;
LOOP
FETCH _refCursor INTO _record;
IF NOT FOUND THEN
EXIT;
END IF;
RAISE NOTICE 'Field: %', _record.field;
RAISE NOTICE 'Value: %', _record.value IS NULL;
END LOOP;
CLOSE _refCursor;
END;
$BODY$;
并且我尝试用plpgsql语言调用存储并且工作正常。
DO
$$
DECLARE
parameters udtt_input_param[] := ARRAY[
ROW('YED','Yeti')
,ROW('INTELLIGENT','NOOB')
,ROW('ZXC',NULL)
,ROW('CXX','1')];
BEGIN
CALL stored_example(parameters);
END
$$
LANGUAGE plpgsql
C# Npgsql (nuget Npgsql 4.1.4)
// mapping global type on Startup.cs
NpgsqlConnection.GlobalTypeMapper.MapComposite<UdtSpParameter>("udt_sp_parameter");
// class model UdtSpParameter
public class UdtSpParameter
{
[PgName("field")]
public string Field { get; set; }
[PgName("value")]
public string Value { get; set; }
public UdtSpParameter() { }
}
// call stored procedure at data access layer for example StudentDAL.cs
public IEnumerable<T> CallStoredResultSet<T>(UdtSpParameter[] inputParameters ) where T : class
{
var conn = _GetOpenConnection();
var tran = _BeginTransaction(conn);
NpgsqlCommand command = new NpgsqlCommand("stored_example", conn);
command.CommandType = CommandType.StoredProcedure;
var cmdParam = command.CreateParameter();
cmdParam.ParameterName = "parameters";
cmdParam.DbType = DbType.Object;
cmdParam.Value = inputParameters;
cmdParam.DataTypeName = "udt_sp_parameter";
command.Parameters.Add(cmdParam);
// throw exception here
// Can't write CLR type Web.API.Models.UdtSpParameter[] with handler type MappedCompositeHandler`1
NpgsqlDataReader dr = command.ExecuteReader();
var result = new List<T>();
while (dr.Read())
{
Console.WriteLine(dr[0].ToString(), dr[1].ToString());
}
_CommitTransaction(tran);
_CloseConnection(conn);
return result;
}
如果我做错了什么,请找些东西告诉我改正。提前致谢。
您出现此错误是因为您为参数指定了类型名称,该参数是复合类型而不是复合数组。因此,您应该将 udt_sp_parameter[]
指定为 DataTypeName
的值,而不是 udt_sp_parameter
:
var cmdParam = command.CreateParameter();
cmdParam.ParameterName = "parameters";
cmdParam.Value = inputParameters;
cmdParam.DataTypeName = "udt_sp_parameter[]";
由于您的类型已注册并且驱动程序已经知道其 PostgreSQL 名称,因此无需在参数设置期间指定它。请随意删除上面代码的最后一行:
var cmdParam = command.CreateParameter();
cmdParam.ParameterName = "parameters";
cmdParam.Value = inputParameters;
在大多数情况下,驱动程序足够智能,可以自动检测类型,但是当有歧义时,应该指定它。例如,您有一个应作为 JSON 传递的字符串,或者应将 CLR 类型序列化为 JSON。在其他情况下,只依赖于驱动程序的内部结构并让他完成他的工作。
Npgsql的官方文档说:
The only way to call a stored procedure is to write your own CALL my_proc(...) command, without setting CommandBehavior.StoredProcedure.
在您的特定情况下,您应该像这样修改代码:
NpgsqlCommand command = new NpgsqlCommand("call stored_example(:parameters)", conn);
// comment this line command.CommandType = CommandType.StoredProcedure;
希望对兄弟有帮助