必须使用Oracle.EntityFrameworkCore包,它基于纯托管的Oracle.ManagedDataAccess.Core,支持.NET 6+及全平台,连接字符串需用Easy Connect格式避免ORA-12154错误,并注意libaio依赖和NLS_LANG环境变量配置。

直接用 Oracle.EntityFrameworkCore 包,别碰 System.Data.OracleClient
System.Data.OracleClient 已被微软标记为废弃(.NET Framework 4.0+ 就不推荐用了),且在 .NET Core / .NET 5+ 中根本不可用——它依赖 Windows 原生 Oracle 客户端 DLL,跨平台跑不起来,Linux/macOS 直接报 DllNotFoundException。你看到的“装客户端 + 配 Path”方案,只适用于旧版 .NET Framework 的 ASP.NET Web Forms 或 MVC,对 ASP.NET Core 无效。
正确路径只有一条:用 Oracle 官方维护的 Oracle.EntityFrameworkCore NuGet 包。它基于 Oracle.ManagedDataAccess.Core,纯托管实现,无需本地 Oracle Client,Windows/Linux/macOS 全平台可用。
- 必须用 .NET 6+(.NET Core 3.1 已 EOL,Oracle 官方从 2023 年起只支持 .NET 6 及以上)
- 对应 EF Core 版本要匹配:例如 EF Core 8.x → 用
Oracle.EntityFrameworkCore 8.22.2(版本号末两位代表 Oracle 数据库兼容版本,如 22 表示支持 Oracle 21c/19c/12c) - 连接字符串里不要写
Persist Security Info=True—— 这个参数在托管驱动中被忽略,还可能触发警告
连接字符串怎么写才不报 ORA-12154
ORA-12154 是最常见的错误,本质是“找不到服务名”,不是密码错、不是网络不通。根源在于你用了 TNSNAMES.ORA 方式(比如 Data Source=ORCL),但没配 TNS 文件,或路径不对;而 ASP.NET Core 运行时根本不会读取你本地 Oracle 安装目录下的 tnsnames.ora。
唯一可靠写法是使用 Easy Connect 格式(即完整描述式):
Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.100)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ORCLPDB1)));User Id=myuser;Password=mypass;
-
SERVICE_NAME不是 SID —— Oracle 12c+ 默认用 PDB,查数据库时执行SELECT SYS_CONTEXT('USERENV', 'CON_NAME') FROM DUAL;确认实际服务名 - 如果数据库启用了 SSL,需追加
(SECURITY=SSL)并配置信任证书,否则连接会静默超时 - Linux 容器部署时,
HOST不能填localhost—— 容器内 localhost 指自己,要填宿主机 IP 或 Docker 网络别名
TransactionScope 跨 Oracle 连接会静默失败
如果你在同一个 TransactionScope 里开了两个 OracleConnection(哪怕连的是同一个 Oracle 实例),或者混用 Oracle + SQL Server,事务一定不生效,且不会抛异常 —— Oracle.ManagedDataAccess.Core 自 2021 年起已移除对 System.Transactions 分布式事务的支持,Enlist=true 参数只是摆设。
现象是:第一个连接 Commit 成功,第二个连接也 Commit 成功,但两者不原子。你以为回滚了,其实只回滚了最后一个。
- 单库多连接?用同一个
OracleConnection实例,手动控制BeginTransaction()和Commit() - 跨库/跨服务?放弃强一致性,改用 outbox 表 + 后台轮询(例如用
IHostedService扫描状态为 pending 的记录,发消息或调 API) - EF Core 中想保证单库事务原子性?确保所有 DbSet 操作都在同一个
DbContext实例内完成,别 new 多个上下文
Linux 上连不上?先检查 libaio 和字符集
CentOS/RHEL 8+、Ubuntu 22.04 等新版系统默认不带 libaio,而 Oracle 托管驱动底层依赖它做异步 I/O。缺这个库,连接会卡死在 Open(),超时后抛 OracleException: ORA-12170: TNS:Connect timeout,而不是更明确的错误。
另外,Oracle 服务端字符集(如 AL32UTF8)和客户端环境变量不一致时,中文字段读出来是乱码或空字符串,但日志里完全没提示。
- 安装
libaio:sudo apt install libaio1(Ubuntu)或sudo yum install libaio(RHEL/CentOS) - 设置环境变量:
export NLS_LANG=AMERICAN_AMERICA.AL32UTF8(值需和服务端一致,查SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER = 'NLS_CHARACTERSET';) - Docker 镜像里记得把这行加进
Dockerfile:ENV NLS_LANG=AMERICAN_AMERICA.AL32UTF8
真正麻烦的从来不是连上,而是连上之后发现事务不生效、中文变问号、容器里死活超时——这些点不提前踩一遍,上线后排查成本远高于写代码本身。


















