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

如何在EF中使用命名参数调用PostgreSQL函数?

解决EF Core调用PostgreSQL带默认参数函数的问题

问题背景

调用PostgreSQL函数时,第一个参数sys_args有默认值无需传递,用NpgsqlConnection+NpgsqlCommand(设置CommandType.StoredProcedure并开启Npgsql.EnableStoredProcedureCompatMode)可以正常执行,但用EF Core的FromSqlRaw生成的SQL会报错:

42883: function frames.frm_tv_service_insert(integer, integer, integer, date) not found

EF生成的SQL语句为:

select result_err_out,result_text_out,result_text_body,data from frames.frm_tv_service_insert(@idnv,@idvid_rem,@place_idm_work,@datesv)

目标函数的定义签名:

CREATE OR REPLACE FUNCTION frames.frm_tv_service_insert(
    sys_args json DEFAULT '[{"Name":"idm_workdl","Value":[21,28,25,20,30]},{"Name":"userid","Value":"2790a07d-ccf5-4720-8e5c-59817743440c"}]'::json,
    idnv integer DEFAULT NULL::integer,
    idvid_rem integer DEFAULT NULL::integer,
    place_idm_work integer DEFAULT NULL::integer,
    datesv date DEFAULT NULL::date)
RETURNS TABLE(result_err_out integer, result_text_out text, result_text_body text, data json)
LANGUAGE plpgsql ...

报错原因

PostgreSQL通过参数的数量、类型、顺序匹配函数重载。EF生成的位置参数调用会把传入的4个参数对应到函数的前4个参数(第一个参数是sys_args,类型为json),但我们传入的是integer/date类型,PostgreSQL找不到匹配的函数签名,因此抛出错误。

解决方案

使用PostgreSQL的命名参数语法(参数名 := 参数值),明确指定每个参数对应的函数参数,跳过有默认值的sys_args,让PostgreSQL正确匹配函数。

方案1:直接构造带命名参数的SQL

// 构造带命名参数的SQL语句
var functionSql = @"select result_err_out,result_text_out,result_text_body,data 
                    from frames.frm_tv_service_insert(
                        idnv := @idnv, 
                        idvid_rem := @idvid_rem, 
                        place_idm_work := @place_idm_work, 
                        datesv := @datesv)";

// 定义参数(确保参数名和函数参数名一致)
var parameters = new[]
{
    new NpgsqlParameter("@idnv", yourIdnvValue),
    new NpgsqlParameter("@idvid_rem", yourIdvidRemValue),
    new NpgsqlParameter("@place_idm_work", yourPlaceIdmWorkValue),
    new NpgsqlParameter("@datesv", yourDatesvValue)
};

// 执行查询
var result = await new MyDataContext()
    .ResultMessageJsons
    .FromSqlRaw(functionSql, parameters)
    .FirstAsync();

方案2:动态生成命名参数SQL(适配任意函数和参数)

如果需要动态指定函数名和参数,可以封装方法自动拼接命名参数部分:

public static async Task<ResultMessageJson> ExecEFFunctionAsync(
    string functionName, 
    MyDataContext context, 
    NpgsqlParameter[] parameters)
{
    // 拼接命名参数赋值语句,去掉参数名前的@符号
    var paramAssignments = string.Join(", ", 
        parameters.Select(p => $"{p.Name.TrimStart('@')} := {p.Name}"));
    
    // 构造完整SQL
    var sql = $"select result_err_out,result_text_out,result_text_body,data from {functionName}({paramAssignments})";
    
    // 执行查询
    return await context.ResultMessageJsons
        .FromSqlRaw(sql, parameters)
        .FirstAsync();
}

// 调用示例
var paramsArray = new[]
{
    new NpgsqlParameter("idnv", yourIdnvValue), // 参数名直接用函数参数名,无需@
    new NpgsqlParameter("idvid_rem", yourIdvidRemValue),
    new NpgsqlParameter("place_idm_work", yourPlaceIdmWorkValue),
    new NpgsqlParameter("datesv", yourDatesvValue)
};

var result = await ExecEFFunctionAsync("frames.frm_tv_service_insert", new MyDataContext(), paramsArray);

注意事项

  • 无需设置AppContext.SetSwitch("Npgsql.EnableStoredProcedureCompatMode", true),因为我们是直接用SELECT语法调用函数,而非存储过程调用方式。
  • 确保NpgsqlParameter的Name属性和PostgreSQL函数的参数名完全一致(PostgreSQL默认大小写敏感)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.02 06:34:53