The Contenders
Dapper
Dapper is a hybrid ORM. This is a great ORM for those who have a lot of ADO legacy code to convert. Dapper uses SQL queries and parameters can be used just like ADO, but the parameters to a query can be simplified into POCOs. Select queries in Dapper can also be translated into POCOs. Converting legacy code can be accomplished in steps because the initial pass of conversion from ADO is to add Dapper, followed by a step to add POCOs, then to change queries into LINQ (if desired). The speed difference in my tests show that Dapper is better than my implementation of ADO for select queries but slower for inserts and updates. I would expect ADO to perform the best, but there is probably a performance penalty for using the data set adapter instead of the straight sqlCommand method.
If you’re interested in Dapper you can find information here: Stack Exchange/Dapper. Dapper has a NuGet package, which is the method I used for my sample program.
ADO
I rarely use ADO these days, with the exception of legacy code maintenance or if I need to perform some sort of bulk insert operation for a back-end system. Most of my projects are done in Entity Framework, using the .Net Core or the .Net version. This comparison doesn’t feel complete without including ADO, even though my smackdown series is about ORM comparisons. So I assembled a .Net console application with some ADO objects and ran a speed test with the same data as all the ORM tests.
NHibernate
NHiberate is the .Net version of Hibernate. This is an ORM that I used at a previous company that I worked for. At the time it was faster than Entity Framework 6 by a large amount. The .Net Core version of Entity Framework has fixed the performance issues of EF and it no longer makes sense to use NHibernate. I am providing the numbers in this test just for comparison purposes. NHibernate is still faster than ADO and Dapper for everything except the select. Both EF-7 and NHibernate are so close in performance that I would have to conclude that they are the same. The version of NHibernate used for this test is the latest version as of this post (version 4.1.1 with fluent 2.0.3).
Entity Framework 7 for .Net Core
I have updated the NuGet packages for .Net Core for this project and re-tested the code to make sure the performance has not changed over time. The last time I did a smackdown with EF .Net Core I was using .Net Core version 1.0.0, now I’m using .Net Core 1.1.1. There were no measurable changes in performance for EF .Net Core.
The Results
Commenter Popovici Liviu has run the latest numbers. Here are the results:
“The EF, Dapper, and ADO were updated to the last version available on 8 Feb 2022.”
Here are the old results side-by-side with the .ToList() method helper and without:
Test for Yourself!
First, you can download the .Net Core version by going to my GitHub account here and downloading the source. There is a SQL script file in the source that you can run against your local MS SQL server to setup a blank database with the correct tables. The NHibernate speed test code can also be downloaded from my GitHub account by clicking here. The ADO version is here. Finally, the Dapper code is here. You’ll want to open the code and change the database server name.
What about all the other features of NHibernate though? NHibernate being the fastest while also having a feature set that is far more complete than any of the others, should still give it an edge? For instance custom type support, graph parsing with add/attach/update based on id, etc. Also, EFCore 2.0 is out, so would be nice to update the article … 😉
Coming soon. I’m currently working with EFCore 2.0 a lot and it is fast. We’ll see if Microsoft has caught up to NHibernate.
So, has it? Is there any reason to switch from latest .net core to nhibernate now?
My experience is that Microsoft has done a good job of playing catch-up with NHibernate. The unit testing tools available for EF core are nice, particularly the in-memory unit testing feature. Also, there are a missing features in NHibernate that made it annoying, so I would recommend sticking with EF Core. I have used EF Core for several of the newer WebApi projects that my company has in production use and the performance is excellent. If you can afford the man-hours to test your real-time application, make a copy and do one in NHibernate and one in EF Core. Then you’ll know for sure what the performance difference is. If you can’t measure it or “feel” it, then stick with EF Core. The difference between NHibernate and EF 4.0 was physically noticeable and that’s why I used NHibernate in the past.
I updated to the latest of all nuget packages and changed to dotnetcore2, same speeds though… ;(
To be fair when you call you are `ToList()` your select’s shouldn’t you also call AsNoTracking()
This information is dangerous.
Without ToList, all you are doing is creating an executable expression tree. When you add ToList, the expression tree is executed and the query gets sent to the database.
That’s why I recommend downloading the sample code and performing your own tests. I always test a new technology against existing data to see how it will perform in a somewhat real-world environment. Your application may require the use of ToList, or you might do something asynchronously.
Async has nothing to do with it. Your implementation without ToList has zero interaction with the database. You are essentially saying it takes Dapper 8.6 seconds to query a database server and hydrate some results and it takes EF Core 0.01 seconds to build an in memory expression tree .
I get what you’re saying, and it’s not a “fair” comparison of database ORMs. Maybe a better method of comparing ORMs would be to query the data and spit the results onto a console. The console will slow down the process, but it should be equal across all ORMs. All data will be read from the database. I’ll give this a try, with and without converting to a table and see how each compare.
I feel obligated to chime in here. Dapper, Ef, NHibernate, and any other ORM are layers of code built on top of ADO. Active X Objects. ADO.Net the tech used to access ADO via a .net managed code will be irrelevant here. I am mostly concerned with the ADO appearing in your tests. All ORM’s ultimately have one way to send a query to a db and that is via a string containing the query. Further, all receive the exact same thing back. A DataReader stream. At this point, ORM’s do there thing, reading the DataReader and converting the resulting data into a object of which we consume in code. Dapper happens to generate a function that does this conversion/serialization from DataReader to a class instance and it stores this function so that it knows how to do that object in a dictionary so thet it need not Emit the function again the next go around. Commonly other ORM’s generate this mapping each go around. ORM’s tend to offer a bunch of additional features such as object tracking and includes. This is where Dapper lacks. Bottom line is knowone should put ADO in there ORM tests as the only one to get raw ADO code to be slower then any ORM is to write poorly written C# code. Say trying to reader.ToString() every column in the Row returned by DataReader then parse with a int.TryParse or something like that rather then calling reader.GetInt(“col1”) or reader.GetString(“col2”). As say this knowing that sending query to db and reading the results all ORM’s I beleive execute probably the exact same code and its only after this that ORM’s get to work. Say allowing a column called “employeeId” to map to a class property called “EmpId”. Just my opinions based on what I think I know about ORM’s though and I could very well be wrong.
1. What are the numbers in the tables? Which unit do they have (count, milliseconds, ???) and how was tested (input + method (static, dynamic, random data???))
The numbers in seconds (I should have specified this). The code and data used for these measurements are included in the links at the bottom of the article. I used a static set of data for all tests. With that said, this article was written quite some time ago. Dapper, EF, and NHibernate have had multiple upgrades since then. If you are trying to decide which to use, I would recommend downloading the code, upgrade the ORMs, and rerunning them on your system. If you’re researching to use this in the cloud or our company system, I would attempt to run these tests on those systems to get real-world sample data.
I can’t upload an image but i took the projects, updated and ran. Here are the results:
EF Core Dapper ADO
INSERT 0.765 s 2.394 s 2.042 s
UPDATE 0.389 s 2.449 s 1.939 s
SELECT 5.091 s 8.851 s 15.531 s
DELETE 0.296 s 0.011 s 0.010 s
The EF, Dapper and ADO were updated to the last version available on 8 Feb 2022.