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

Entity Framework Core执行PostgreSQL查询时出现格式异常

解决PostgreSQL EF Core中"Input string was not in correct format"异常

这个问题我之前遇到过,根源是字符串格式化时的占位符冲突,咱们一步步拆解原因和解决方案:

问题原因

你定义的_RFS_QUERY_FILTER里包含大量JSON格式的{和}字符,而EF Core的FromSql在处理带参数的SQL字符串时,会调用.NET的String.Format来解析{0}这种占位符。但JSON里的{}会被String.Format误判为额外的格式占位符(因为它只认{数字}的规范格式),导致解析失败抛出FormatException。

解决方案

这里有两种可靠的解决方式,推荐第二种参数化查询(更安全,还能防SQL注入):

方式1:转义JSON中的{}字符

把JSON里的每个{替换成{{,每个}替换成}},这样String.Format会把它们当成普通字符处理,而不是占位符:

// 转义JSON中的{}为{{}},避免被String.Format误解析
private const string _RFS_TAG = "NEW_RFS_WLI";
private const string _RFS_QUERY_FILTER = "'{{\"bsareadyforservicewli\": {{\"messageheader\": {{\"messagetype\": \"{0}\"}}}}}}'";
// 先预解析RFS标签到过滤条件中
private const string _RESOLVED_RFS_FILTER = string.Format(_RFS_QUERY_FILTER, _RFS_TAG);

// 查询语句中的{0}是entry point的参数,正常保留
private const string _LATEST_RFS_FOR_ENTRY_POINT_QUERY = @"
SELECT o.* FROM connectivity_order_entry_points as oep 
INNER JOIN connectivity_orders as o 
ON oep.connectivity_order_id = o.id 
INNER JOIN connectivity_order_updates as ou 
ON o.id = ou.connectivity_order_id 
WHERE oep.connectivity_entry_point_id = {0} AND 
ou.data @> {1} 
ORDER BY ou.id DESC 
LIMIT 1;";

// 调用方法
public async override Task<Order> GetActiveOrderForEntryPoint(int id) {
    var sql = string.Format(_LATEST_RFS_FOR_ENTRY_POINT_QUERY, id, _RESOLVED_RFS_FILTER);
    return await Context.Orders.FromSql(sql).FirstOrDefaultAsync();
}

方式2:使用参数化查询(推荐)

直接用PostgreSQL的参数占位符(比如@paramName),配合EF Core的参数传递,完全避免字符串格式化的问题,还能防止SQL注入:

private const string _RFS_TAG = "NEW_RFS_WLI";

// 定义带参数占位符的SQL语句
private const string _LATEST_RFS_FOR_ENTRY_POINT_QUERY = @"
SELECT o.* FROM connectivity_order_entry_points as oep 
INNER JOIN connectivity_orders as o 
ON oep.connectivity_order_id = o.id 
INNER JOIN connectivity_order_updates as ou 
ON o.id = ou.connectivity_order_id 
WHERE oep.connectivity_entry_point_id = @entryPointId AND 
ou.data @> @rfsFilter::jsonb 
ORDER BY ou.id DESC 
LIMIT 1;";

// 调用方法
public async override Task<Order> GetActiveOrderForEntryPoint(int id) {
    // 用序列化构建JSON过滤条件,避免手动拼接字符串
    var rfsFilter = JsonSerializer.Serialize(new {
        bsareadyforservicewli = new {
            messageheader = new {
                messagetype = _RFS_TAG
            }
        }
    });

    // 传递参数,EF Core会自动处理参数绑定
    return await Context.Orders.FromSql(_LATEST_RFS_FOR_ENTRY_POINT_QUERY,
        new NpgsqlParameter("@entryPointId", id),
        new NpgsqlParameter("@rfsFilter", rfsFilter))
        .FirstOrDefaultAsync();
}

验证说明

第二种方式的优势很明显:不需要处理繁琐的转义,还能确保参数的安全性,尤其是当JSON结构复杂时,序列化的方式比手动拼接字符串更不容易出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:13:37