Oracle.EntityFrameworkCore 在 .NET 7 下性能不如 Dapper,根本原因是设计哲学不同:前者为全功能 ORM,存在 LINQ 解析开销与表达式树翻译瓶颈,如 Where(x => x.CreatedAt.Date == DateTime.Today) 被译为低效 TRUNC(created_at) = TRUNC(SYSDATE),无法利用函数索引;后者为精简 SQL 执行器,支持手写高效 SQL。
Oracle.EntityFrameworkCore 在 .NET 7 下性能不如 Dapper,根本原因不是版本兼容问题,而是两者设计哲学和执行路径完全不同——前者是全功能 ORM,后者是精简的 SQL 执行器。
Oracle.EntityFrameworkCore 的 LINQ 解析开销明显
ef core 对 oracle.entityframeworkcore 提供商的适配仍存在表达式树翻译瓶颈。比如 where(x => x.createdat.date == datetime.today) 这类操作,在 oracle 上常被翻译成低效的 trunc(created_at) = trunc(sysdate),且无法利用函数索引;而 dapper 直接执行你写的 sql,你可以手写 created_at >= trunc(sysdate) and created_at 并加索引。
常见现象:
- 同一查询在 EF Core 中执行耗时 120ms,在 Dapper 中仅 18ms
-
Oracle.EntityFrameworkCore默认启用变更跟踪(AsNoTracking()必须显式加) - 复杂 JOIN 查询生成的 SQL 常含冗余子查询或未绑定参数
Dapper 的 TypeDeserializerCache 几乎零反射开销
Dapper 内部通过 SqlMapper.TypeDeserializerCache 静态缓存类型映射逻辑,首次查询后后续同类型结果集反序列化几乎不走反射;而 Oracle.EntityFrameworkCore 每次都需通过 PropertyInfo.SetValue 和状态管理器更新实体,尤其在批量读取时放大差异。
实操建议:
- 用
Dapper时,确保目标类型是public class且属性为public set,否则缓存失效退化为慢反射 - 避免在 Dapper 中混用
dynamic和强类型——dynamic不进缓存,性能掉一档 -
Oracle.EntityFrameworkCore若必须用,至少加.AsNoTracking().ToList(),否则额外承担变更追踪内存开销
Oracle 特定驱动层的缓冲与参数绑定差异
Oracle.EntityFrameworkCore 依赖 Oracle.ManagedDataAccess.Core(ODP.NET),其参数绑定默认启用 BindByName = false,按位置绑定易出错;而 Dapper 统一走 IDbCommand.Parameters.Add() + @name 占位符,更贴近 Oracle 原生协议。
容易踩的坑:
-
Oracle.EntityFrameworkCore对CLOB/BLOB字段读取默认加载整块内容到内存,Dapper 可用OracleClob流式读取 - EF Core 的连接池复用策略与 Oracle 官方驱动不完全对齐,高并发下偶发
ORA-01000: maximum open cursors exceeded - Dapper 的
Query<t>()</t>默认不开启事务,EF Core 的DbSet<t>.Find()</t>却隐式开只读事务,增加 round-trip











