System.NotSupportedException: 具有多个查询的命令不能有 out 参数

System.NotSupportedException: Commands with multiple queries cannot have out parameters

我 运行 遇到另一个问题,即在带有多个引用游标的存储过程周围使用数据 reader。我收到一个不受支持的异常。不幸的是,我可以从 npgsql 的源代码中看到它的来源,但是..我不确定我是否同意抛出该异常。我们编写的代码适用于 oracle(完全托管和托管类型),sql 服务器。感谢任何帮助使它在 api 的某些关键 dbms 风格中保持一致。

存储过程体

CREATE OR REPLACE FUNCTION public.getmultipleresultsets (
    v_organizationid integer)
    RETURNS Setof refcursor
    LANGUAGE 'plpgsql'

AS $BODY$

declare       public override void AddCursorOutParameter(DbCommand command,
        string RefCursorName)
    { 
        NpgsqlParameter parameter = (NpgsqlParameter)CreateParameter(RefCursorName, false);
        parameter.NpgsqlDbType = NpgsqlDbType.Refcursor;
        parameter.NpgsqlValue = DBNull.Value;
        parameter.Direction = ParameterDirection.Output;

        command.Parameters.Add(parameter); 
    }
cv_1 refcursor;
cv_2 refcursor;

BEGIN 

    open cv_1 for
    SELECT a.errorCategoryId, a.name, a.bitFlag
    FROM ErrorCategories a
    ORDER BY name;
    RETURN next cv_1;

    open cv_2 for
    SELECT * 
    FROM StgNetworkStats  ;
    RETURN next cv_2;

END;

$BODY$;

关键 Reader 包装 postgres 的代码 sql(npgsql 的 Entlib 实现)

private IDataReader DoExecuteReader(DbCommand command, CommandBehavior cmdBehavior)
{
    try
    {

        var sql = new StringBuilder();

        using (var reader = command.ExecuteReader(CommandBehavior.SequentialAccess))
        {
            while (reader.Read())
            {
                sql.AppendLine($"FETCH ALL IN \"{ reader.GetString(0) }\";");
            }
        }

        command.CommandText = sql.ToString();
        command.CommandType = CommandType.Text; 

        IDataReader reader2 = command.ExecuteReader(cmdBehavior);
        return reader2;

    }
    catch (Exception)
    {
        throw;
    }
}

命令构建代码如下所示

 Helper.InitializeCommand(cmd, 300, "getmultipleresultsets");
    db.AddReturnValueParameter(cmd);

    db.AddInParameter(cmd, "organizationId", DbType.Int32, ORGANIZATIONID);

    db.AddCursorOutParameter(cmd, "CV_1");
    db.AddCursorOutParameter(cmd, "CV_2

添加 refcursor 参数的代码是这样的

您上面的代码似乎使 PostgreSQL 函数与试图读取其结果的 .NET 客户端代码混淆。

无论如何,您的函数被声明为 return 一组 refcursors - 这与两个输出参数不同;您似乎混淆了游标的名称(例如,游标有名称,但没有整数)与 参数 的名称(int 参数确实有名称)。

请注意 PostgreSQL 实际上没有输出参数 - 函数总是 return 一个 table,仅此而已。 PostgreSQL 确实有带输出参数的函数语法,但这只是构造输出模式 table 的一种方式。这与 SQL 服务器不同,它显然可以 return 同时具有 table 一组命名输出参数。为了促进可移植性,在读取结果时,如果 Npgsql 看到任何方向为 out 的 NpgsqlParameter,它将尝试查找具有参数名称的结果集,并将简单地使用该列第一行的值填充 NpgsqlParameter 的值。与简单地自己阅读结果集相比,这种做法的附加值为零 - 它只是为了兼容性。

总而言之,我建议您使用 reader 阅读 refcursors,然后适当地获取它们的结果。