Published
- 4 min read
Tier-ranking every .NET ORM (so you know which one to pick)
Early in 2022, I bought the source code of a .NET web application from a Codester, an online marketplace for scripts and apps.
The reason?
I wanted to have some ready-made snippets for my blog and for social media.
Since I’ve paid the entire application $40 USD, I haven’t had high expectations.
But I was still disappointed:
- Wasn’t able to run the app
- Poorly organized and not cleaned up code
- Use of static classes and methods all throughout
- No tests at all
- Custom-made ORM
Out of the all things in the codebase, I find the most issues with the custom-made ORM.
I’ll share at the end of the post the issues I’ve found, but here’s a piece of advice:
If you need to introduce an ORM in your code, use an existing one.
Everything else leads to wasted time, code, and bugs.
To help you with your next ORM selection, I’ve made a list of ORM tools I recommend. Starting from the best ones to worse ones.
Let’s dive in.
S-Tier: Entity Framework Core
Link: https://learn.microsoft.com/en-us/ef/core/
What is it:
The official ORM inside .NET, maintained by Microsoft.
Description/observation:
The king of ORMs.
Start with Entity Framework Core on most greenfield projects.
Migrations, change tracking, and LINQ queries cover the majority of what typical business applications need. It’s Microsoft-backed, so maintenance risk is as low as it gets in the .NET ecosystem.
Supported databases:
SQL Server, PostgreSQL, MySQL, SQLite, Oracle, and many others through providers. 44 total providers at the time of writing this.
When to use:
In the majority of cases: CRUD apps, enterprise systems, monoliths, microservices.
S-Tier: Dapper
Link: https://github.com/DapperLib/Dapper
What is it:
A lightweight micro-ORM built by the team at Stack Overflow.
Description/observation:
Dapper is extremely fast because it is very close to raw SQL.
It doesn’t support migrations, but its sole purpose is to map the results of SQL queries to objects.
Supported databases:
Anything that ADO.NET supports: SQL Server, Oracle, MySQL, PostgreSQL, SQLite…
When to use:
Use Dapper instead of EF Core in 3 cases:
- You are migrating from ADO.NET to a more modern approach.
- EF Core’s generated SQL becomes a problem. (But in that case, I would try to understand what kind of LINQ is used, and see if it’s possible to optimize it. Based on my experience, most likely it is.)
- The team is comfortable with and experienced in using SQL.
A-Tier: NHibernate
Link: https://nhibernate.info/
What is it:
A mature ORM inspired by Hibernate from the Java world.
Description/observation:
It was very popular before EF Core became a mainstream ORM.
These days, I only see it in job advertisements alongside .NET Framework and ASP.NET MVC / Web Forms combo.
It supports advanced mapping scenarios and complex domain models, but the learning curve is steeper compared to EF Core.
Supported databases:
SQL Server, PostgreSQL, MySQL, Oracle, SQLite, and many more.
When to use:
Avoid NHibernate on new projects. If you’re maintaining a codebase that already uses it, that’s a different conversation, but there’s no good reason to start with it today.
A-Tier: linq2db
Link: https://github.com/linq2db/linq2db
What is it:
A lightweight data access library focused on high-performance LINQ to SQL.
Description/observation:
It sits somewhere between EF Core and Dapper.
You get strong LINQ support, but without the change-tracking system and other overhead that EF Core brings.
Supported databases:
Wide range including SQL Server, PostgreSQL, MySQL, SQLite, and Oracle.
When to use:
When EF Core feels too heavy, and Dapper is too raw. Or when you are addicted to LINQ code style.
B-Tier: Marten
Link: https://github.com/JasperFx/marten
What is it:
A document database and event sourcing library built on top of PostgreSQL.
Description/observation:
Marten is not a traditional ORM, where you use it to query relational databases.
Instead, it treats PostgreSQL as a document store.
It’s built for event-sourced systems and document-heavy applications.
Supported databases:
PostgreSQL only.
When to use:
For event sourcing and document-style persistence with PostgreSQL.
C-Tier: SQLKata
Link: https://github.com/sqlkata/querybuilder
What is it:
A fluent SQL query builder for C#.
Description/observation:
It’s more of a query builder than an ORM. It helps you build safe and clean SQL queries.
Supported databases:
SQL Server, SQLite, PostgreSQL, MySQL, Firebird.
When to use:
If you want something that maps objects, tracks changes, and manages relationships automatically, this is not the tool.
If you want elegant and safe SQL queries, SqlKata fits perfectly.
D-Tier: Custom-made ORM
And here we are.
This is what started the whole article.
After digging through the $40 codebase I bought, here are the issues I found in the custom ORM:
- SQL injection in code, and a lack of prevention of it.
- The transaction API is not properly implemented.
- Connection is sometimes used as a private field, sometimes a method creates its own connection.
- Opening a new connection swallows the real exception.
- Commented-out code all over the ORM.
- No tests.
Six problems.
But all of them could have been avoided if the developer had used any of the tools listed above.
You can easily build an initial version of ORM.
But you will spend 10x as many hours maintaining and debugging it.
Honorary mentions
Here are some additional ORMs that didn’t make the list, but I collected them during the research for the article.
The reason I would avoid them is that they are not being actively maintained anymore:
Every Friday I reveal insights with frameworks, tools & easy-to-implement strategies you can start using almost overnight.
Join the inner circle of 14,000+ .NET developers