安装npgsql包需区分用途:纯ado.net用npgsql,ef core用npgsql.entityframeworkcore.postgresql;连接字符串须含password和timeout;参数用:name非@name;异步操作必须await;连接池需合理配置。

安装 Npgsql 包时别漏掉 Npgsql 和 Npgsql.EntityFrameworkCore.PostgreSQL 的区别
直接用 Npgsql 做 ADO.NET 操作,和用 EF Core 是两套路径。新手常在 NuGet 里搜 “postgres” 顺手装了 Npgsql.EntityFrameworkCore.PostgreSQL,结果写 NpgsqlConnection 时发现类型找不到——因为那个包只提供 EF Core 的扩展,不带基础驱动。
- 纯 SQL 执行、手动控制连接/事务:只装
Npgsql - 要用
DbContext+ LINQ 查询:装Npgsql.EntityFrameworkCore.PostgreSQL(它会自动拉取Npgsql作为依赖) - EF Core 7+ 连 PostgreSQL 时,连接字符串里必须加
Server Compatibility Mode=Redshift吗?不用,那是给 Redshift 兼容用的,PostgreSQL 默认不启用
NpgsqlConnection 连接字符串写错会导致 Invalid operation: connection is closed
不是连接没开,是连接根本没成功,但代码里没检查就直接 Open() 或 ExecuteReader(),结果抛出这个看似“已关闭”的误导性错误。
- 典型错误写法:
"Host=localhost;Port=5432;Database=mydb;Username=postgres"—— 少了Password,且没设Timeout,连接卡住几秒后直接超时失败 - 正确写法示例:
"Host=localhost;Port=5432;Database=mydb;Username=postgres;Password=123;Timeout=30" - 连接前务必加
try/catch捕获NpgsqlException,它的SqlState字段能告诉你真实原因(比如28000是认证失败,3D000是数据库不存在)
用 NpgsqlCommand 执行 INSERT 时参数名大小写敏感,且不能用 @ 前缀
PostgreSQL 原生用 $1, $2 占位符,Npgsql 支持命名参数但语法是 :name,不是 SQL Server 风格的 @name。写成 @id 不报错,但参数根本不会绑定,值全为 NULL。
using var cmd = new NpgsqlCommand("INSERT INTO users (name, age) VALUES (:name, :age)", conn);
cmd.Parameters.AddWithValue(":name", "Alice"); // 注意冒号,不是 @
cmd.Parameters.AddWithValue(":age", 25);
- 参数名必须和 SQL 中的
:xxx完全一致(包括大小写),:Name≠:name - 用
AddWithValue要小心类型推断错误,比如传null可能被当成int导致类型不匹配;明确类型推荐用Add:cmd.Parameters.Add(":age", NpgsqlDbType.Integer).Value = 25; - 批量插入别拼 SQL 字符串,用
UNNEST或VALUES多行,Npgsql 支持一次传多个:param数组
异步方法如 ExecuteReaderAsync 必须配合 await,否则线程卡死或连接泄漏
写了 async 方法却忘了 await,或者用 .Result 强制同步等待,在 ASP.NET Core 里极易引发线程池饥饿,表现就是请求变慢、连接堆积、后续请求超时。
- 错误示范:
var reader = cmd.ExecuteReaderAsync().Result;—— 阻塞线程,还可能死锁 - 正确写法:整个调用链保持 async/await,从 Controller Action 到 DAL 层都用
async Task<t></t> - 注意
NpgsqlConnection.OpenAsync()也得 await,不是只有查询才需要 - 如果真要同步(比如老项目无法改 async),至少用
Open()+ExecuteReader(),别混用同步/异步 API
Pooling 默认是 true,本地开发时容易忽略连接未释放导致“too many clients”错误;实际部署还要看 Max Pool Size 和数据库的 max_connections 是否匹配——这点不调参,压测时第一个崩的往往就是连接池。










