首页 > 解决方案 > 如何将复合类型传递给 PL/pgsql 函数?

问题描述

我正在尝试(不成功)将 PostgreSql 复合类型传递给 PL/pgsql 函数。下面列出了错误消息和示例代码。我还尝试了几种不同的代码变体(例如没有成功 - 每个版本都会生成不同的错误消息)。我是 SQL 新手,希望我犯了一个简单的错误。如果有人可以查看下面的示例代码并解释我犯了什么错误,我将不胜感激。

错误信息

    System.InvalidCastException:指定 NpgsqlDbType.Enum 时,必须同时指定 SpecificType
       在 Npgsql.TypeHandlerRegistry.get_Item(NpgsqlDbType npgsqlDbType,类型 specificType)
       在 Npgsql.NpgsqlParameter.ResolveHandler(TypeHandlerRegistry 注册表)
       在 Npgsql.NpgsqlParameter.Bind(TypeHandlerRegistry 注册表)
       在 Npgsql.NpgsqlCommand.ValidateParameters()
       在 Npgsql.NpgsqlCommand.d__71.MoveNext()
    --- 从先前抛出异常的位置结束堆栈跟踪 ---
       在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
       在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)
       在 System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
       在 Npgsql.NpgsqlCommand.d__87.MoveNext()
    --- 从先前抛出异常的位置结束堆栈跟踪 ---
       在 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
       在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)
       在 System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
       在 Npgsql.NpgsqlCommand.ExecuteScalar()
       在 F:\Visual Studio 2017\Projects\TestDatabase\TestDatabase\TestCompositeType.cs:line 42 中的 TestDatabase.TestCompositeType.Test()
       在 F:\Visual Studio 2017\Projects\TestDatabase\TestDatabase\Program.cs:line 17 中的 TestDatabase.Program.Main(String[] args)

系统信息

    Windows 10、64 位
    PostgreSQL 10.3,由 Visual C++ build 1800 编译,64 位
    Npgsql,版本=3.2.6.0

PostgreSql 代码

    如果不存在 MySchema,则创建模式;

    创建类型 MySchema.MyType as(
            X真实,
            Y 实数
        );

    如果不存在则创建表 MySchema.MyTable(
        ItemID int 主键默认生成为identity,
        MyType MySchema.MyType
    );

    创建或替换函数 MySchema.SetMyType(
        ItemID2 整数,
        MyType2 MySchema.MyType
    )
    返回整数
    作为$$
    宣布
        结果ID int;
    开始
        结果ID:=项目ID2;

        如果(存在(从 MySchema.MyTable 中选择 1 作为 mt 其中 mt.ItemID = ItemID2))然后
            插入 MySchema.MyTable( MyType )
            值( MyType2 )
            将 mt.ItemID 返回到 resultID;
        别的
            将 MySchema.MyTable 更新为 mt
            设置 MyType = MyType2
            其中 mt.ItemID = ItemID2;
        万一;

        返回结果ID;
    结尾;
    $$ 语言 plpgsql;

C# 代码

    公共无效测试()
    {
        NpgsqlConnection.MapCompositeGlobally("MySchema.MyType");

        var connection = new NpgsqlConnection("Host=localhost;Username=postgres;Password=123456;database=testdb");
        如果(空==连接)
            throw new NullReferenceException("connection");
        尝试
        {
            连接.打开();

            var cmd = new NpgsqlCommand("MySchema.SetMyType", connection);
            cmd.CommandType = System.Data.CommandType.StoredProcedure;

            var par = new NpgsqlParameter("ItemID2", NpgsqlDbType.Integer);
            par.Value = 1;
            cmd.Parameters.Add(par);

            par = new NpgsqlParameter("MyType2", NpgsqlDbType.Composite);
            我的类型我的类型 = 新的我的类型();
            我的类型.X = 1;
            我的类型.Y = 2;
            par.Value = myType;
            cmd.Parameters.Add(par);

            int id = Convert.ToInt32( cmd.ExecuteScalar() );
        }
        最后
        {
            连接。关闭();
        }
    }   

标签: c#postgresqlplpgsqlnpgsql

解决方案


'sticky bit' 提出的建议纠正了这个问题。我在下面为可能处理相同问题的任何其他人提供了更新的示例代码。使用“ToLower()”将所有字符串转换为小写,但这仅在映射“NpgsqlConnection.MapCompositeGlobally”中的数据库类型时是必需的。

    命名空间测试数据库
    {
        公共类 MyType
        {
            公众持股量 X;
            公众持股量 Y;
        };

        公共类 TestCompositeType
        {
            公共无效测试()
            {
                NpgsqlConnection.MapCompositeGlobally<TestDatabase.MyType>("MySchema.MyType".ToLower());

                var connection = new NpgsqlConnection("Host=localhost;Username=postgres;Password=123456;database=testdb".ToLower());
                如果(空==连接)
                    throw new NullReferenceException("connection");
                尝试
                {
                    连接.打开();

                    var cmd = new NpgsqlCommand("MySchema.SetMyType".ToLower(), 连接);
                    cmd.CommandType = System.Data.CommandType.StoredProcedure;

                    var par = new NpgsqlParameter("ItemID2".ToLower(), NpgsqlDbType.Integer);
                    par.Value = 1;
                    cmd.Parameters.Add(par);

                    par = new NpgsqlParameter("MyType2".ToLower(), NpgsqlDbType.Composite);
                    我的类型我的类型 = 新的我的类型();
                    我的类型.X = 1;
                    我的类型.Y = 2;
                    par.Value = myType;
                    par.SpecificType = typeof( MyType );
                    cmd.Parameters.Add(par);

                    int id = Convert.ToInt32( cmd.ExecuteScalar() );
                }
                最后
                {
                    连接。关闭();
                }
            }
        }
    }


推荐阅读