此主题可能与此Array of composite type as stored procedure input passed by C# Npgsql重复。但这是2017年的旧版本,某些API和属性已弃用。
当前,我正在尝试将一组复合类型传递给存储过程。我确实映射了一个全局复合类型。但是发生了一个异常无法使用处理程序类型MappedCompositeHandler`1编写CLR类型Web.API.Models.UdtSpParameter []
我尝试用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;
}
如果我做错了任何事情,请找点东西,并指出要解决的地方。预先感谢。
答案 0 :(得分:1)
Npgsql 的官方文档说:
<块引用>调用存储过程的唯一方法是编写自己的CALL my_proc(...) 命令,不设置 CommandBehavior.StoredProcedure。
在您的特定情况下,您应该像这样修改代码:
NpgsqlCommand command = new NpgsqlCommand("call stored_example(:parameters)", conn);
// comment this line command.CommandType = CommandType.StoredProcedure;
希望对兄弟有帮助。
答案 1 :(得分:0)
出现此错误是因为您为参数指定了类型名称,该名称是复合类型而不是复合数组。因此,您应该将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。在其他情况下,只需依靠驾驶员内部,然后允许他完成工作即可。