You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C# Npgsql中执行含DO/DECLARE的PostgreSQL脚本?

问题解决方法

直接适配现有代码的修复方案

PostgreSQL的DO匿名块无法直接访问外部传入的参数,必须通过USING子句显式传递参数,并在块内声明对应变量接收。修改PoliciesInsert的SQL语句如下:

public static string PoliciesInsert() =>
@$"DO $$
    DECLARE 
        policy_text varchar(100);
        v_policy varchar(100) := $1;
        v_description varchar(255) := $2;
        v_roles int[] := $3;
        v_user_id int := $4;
    BEGIN
        INSERT INTO common_sch.policies(policy, description)
        VALUES(v_policy, v_description)
        ON CONFLICT ON CONSTRAINT policies_pk
        DO UPDATE SET is_deleted = false
        RETURNING policy INTO policy_text;

        INSERT INTO common_sch.policy_to_role(role_id, policy, created_by, updated_by)
            SELECT 
                unnest(v_roles) as role_id, 
                policy_text as policy, 
                v_user_id as created_by, 
                v_user_id as updated_by
        ON CONFLICT ON CONSTRAINT policy_to_role_unique
            DO UPDATE SET is_deleted = false, updated_by = v_user_id;
    END $$ USING @_Policy, @_Description, @_Roles, @_UserId;";

注意:DO块本身不支持直接返回结果,若需要获取返回值,需额外调整逻辑(比如将结果插入临时表后在块外查询),但这种方式较为繁琐。

更优方案:改用PostgreSQL函数

改用函数可以彻底解决参数绑定问题,同时支持直接返回结果,更符合PostgreSQL最佳实践:

1. 创建PostgreSQL函数

CREATE OR REPLACE FUNCTION common_sch.insert_policies(
    p_policy varchar(100),
    p_description varchar(255),
    p_roles int[],
    p_user_id int
) RETURNS varchar AS $$
DECLARE
    policy_text varchar(100);
BEGIN
    INSERT INTO common_sch.policies(policy, description)
    VALUES(p_policy, p_description)
    ON CONFLICT ON CONSTRAINT policies_pk
    DO UPDATE SET is_deleted = false
    RETURNING policy INTO policy_text;

    INSERT INTO common_sch.policy_to_role(role_id, policy, created_by, updated_by)
        SELECT 
            unnest(p_roles) as role_id, 
            policy_text as policy, 
            p_user_id as created_by, 
            p_user_id as updated_by
    ON CONFLICT ON CONSTRAINT policy_to_role_unique
        DO UPDATE SET is_deleted = false, updated_by = p_user_id;
    
    RETURN policy_text;
END;
$$ LANGUAGE plpgsql;

2. 修改C#查询语句

public static string PoliciesInsert() => 
    "SELECT common_sch.insert_policies(@_Policy, @_Description, @_Roles, @_UserId);";

额外注意事项

  • 原Insert<int>方法的泛型类型为int,但实际返回的是policy字符串(varchar),需根据需求调整为Insert<string>。
  • 函数方式的可维护性、可读性更强,后续修改逻辑只需调整函数即可,无需改动C#代码中的SQL字符串。

内容的提问来源于stack exchange,提问作者LordDraagon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 17:25:38