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

Npgsql 8.0搭配Dapper处理Protobuf重复字段请求时失效

.NET 8 升级 Npgsql 到 8.0 后与 Dapper 配合触发 InvalidCastException 异常

问题场景

在.NET 8环境下,原使用Npgsql 7.x搭配Dapper的代码可正常运行,但升级至Npgsql 8.0后,执行查询时抛出System.InvalidCastException异常。

相关代码

public class Location { public NpgsqlPoint Point { get; set; } }

public async Task<IEnumerable<Location>> GetLocationsAsync(DomainParams paramObject, CancellationToken cancellationToken)
{
    using (NpgsqlConnection conn = new(_connectionString))
    {
        await conn.OpenAsync(cancellationToken);
        return await conn.QueryAsync<Location>("select point from locationsTable where id = ANY(@ids)", new { paramObject.Ids } );
    }
}

异常详情

"Depth": 0,
"HelpURL": null,
"HResult": -2147467262,
"ClassName": "System.InvalidCastException",
"RemoteStackIndex": 0,
"RemoteStackTraceString": null,
"StackTraceString": " at Npgsql.Internal.AdoSerializerHelpers.g__ThrowWritingNotSupported|1_0(Type type, PgSerializerOptions options, Nullable1 pgTypeId, Nullable1 npgsqlDbType, Exception inner)\n at Npgsql.Internal.AdoSerializerHelpers.GetTypeInfoForWriting(Type type, Nullable1 pgTypeId, PgSerializerOptions options, Nullable1 npgsqlDbType)\n at Npgsql.NpgsqlParameter.ResolveTypeInfo(PgSerializerOptions options)\n at Npgsql.NpgsqlParameterCollection.ProcessParameters(PgSerializerOptions options, Boolean validateValues, CommandType commandType)\n at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)\n at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)\n at Npgsql.NpgsqlCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)\n at Dapper.SqlMapper.QueryAsync[T](IDbConnection cnn, Type effectiveType, CommandDefinition command) in /_/Dapper/SqlMapper.Async.cs:line 434"

原因分析

Npgsql 8.0对参数序列化系统进行了重构,默认逻辑与7.x版本存在差异。Dapper自动生成的数组参数(@ids)未被正确识别为PostgreSQL数组类型,导致序列化阶段触发类型转换失败。

解决方案

1. 显式指定参数类型

手动创建参数并明确指定PostgreSQL数组类型,绕过Dapper自动处理的问题:

public async Task<IEnumerable<Location>> GetLocationsAsync(DomainParams paramObject, CancellationToken cancellationToken)
{
    using (NpgsqlConnection conn = new(_connectionString))
    {
        await conn.OpenAsync(cancellationToken);
        var parameters = new DynamicParameters();
        // 根据实际id的数据类型调整NpgsqlDbType,示例为整型数组
        parameters.Add("@ids", paramObject.Ids, NpgsqlDbType.Array | NpgsqlDbType.Integer);
        
        return await conn.QueryAsync<Location>(
            "select point from locationsTable where id = ANY(@ids)", 
            parameters, 
            cancellationToken: cancellationToken
        );
    }
}

2. 回退到旧版参数处理逻辑

若暂时不想修改代码,可在连接字符串中添加配置项,启用Legacy兼容模式:

Server=xxx;Port=5432;Database=xxx;User Id=xxx;Password=xxx;UseLegacyTimestampBehavior=true;UseLegacyAdoNetBehavior=true

注意:该配置为过渡方案,未来版本可能移除,建议优先采用第一种方案。

3. 更新Dapper至最新版本

确保使用的Dapper为最新稳定版,新版本已针对Npgsql 8.0做适配,可能直接解决参数识别问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 02:13:23