I have been writing .NET applications for nearly thirty years, and one of the first decisions on any new project is the data access layer. My answer has been the same for a long time: Dapper, with parameterized T-SQL. Not Entity Framework. Here is why, and it is probably not the reason you expect.
It is not really about performance. Dapper is fast, sitting close to raw ADO.NET, but EF Core has closed most of that gap over the years, and Microsoft documents the tuning work honestly. If raw speed were the whole argument, this post would be out of date already.
The honest reason is control. I have spent as much of my career inside SQL Server as I have inside C#, and SQL is not a problem I need to be protected from. When I write the query myself, I know exactly what is going to hit the database, which indexes it will use, and what the execution plan looks like. When something is slow, I tune a query. I do not reverse engineer what a LINQ expression decided to generate on my behalf.
Dapper was built by the team at Stack Overflow to run Stack Overflow, and it shows. It does one job: run your SQL, map the results to your objects, and get out of the way. The whole library is small enough to actually understand, which is a quality I have come to appreciate more with every year in this business.
To be fair, Entity Framework is a good tool, and I am not here to start a war. If your team lives in LINQ, your schema follows your code, and you lean on migrations, EF Core will serve you well. But my world is usually the opposite: databases that outlive the applications written against them. Just this year I rewrote a web application from 2013 onto .NET 10, and the production database did not change at all. The schema came first, and Dapper never once got in the way of that.
Boring and predictable is not a criticism of a data access layer. After thirty years, boring and predictable is exactly what I want sitting between my application and my data.
No comments: