This article discusses the architectural considerations for choosing between ORMs like EF Core and micro-ORMs like Dapper in modern .NET applications. It argues that the performance gap has narrowed, making developer velocity and architectural clarity more critical factors than raw ORM speed in most production systems. The author highlights that network latency and I/O often dominate request costs, diminishing the impact of micro-optimizations within the ORM layer.
Read original on Dev.to #architectureHistorically, Dapper was favored for its raw performance over EF Core. However, recent advancements in EF Core (versions 7, 8, and beyond) have significantly narrowed this gap, especially in real-world scenarios. Benchmarks that showed Dapper's superiority were often isolated, CPU-bound, single-table queries, which do not reflect typical application architecture where complex object graphs and varied data access patterns are common.
Performance Beyond Microbenchmarks
In production systems, the total request cost is a sum of many factors: middleware processing, authentication, logging, network round-trips to the database, ORM materialization, and serialization. Often, database network latency and I/O operations are the dominant bottlenecks, consuming milliseconds, while ORM materialization occurs in microseconds. This architectural perspective suggests that optimizing the ORM layer alone yields diminishing returns if other system components are slower.
Beyond raw performance, developer velocity and operational stability are critical for long-term system health. EF Core offers compile-time safety due to its LINQ-based queries and strong typing, catching potential database schema mismatches or typos during development. Dapper, relying on raw SQL strings, shifts these errors to runtime, potentially leading to production incidents. This difference impacts incident rates and maintenance overhead over time, highlighting a trade-off between absolute runtime speed and development robustness.
Modern applications frequently deal with complex object graphs, including aggregates, navigation properties, and relationships. EF Core is designed to handle these natively, simplifying queries and projections across multiple related entities with strong typing. Achieving similar results with Dapper often necessitates manual SQL construction, multi-mapping, and custom aggregation logic, which increases code complexity and potential for errors.