Entity Framework (EF) Core, Microsoft's object-to-database mapper library for .NET Framework, brings performance improvements for data updates in version 7, Microsoft claims. The performance of SaveChanges method in EF7 is up to 74% faster than in EF6, in some scenarios.
While EF is widely used in .NET development due to its longevity and backwards compatibility, several benchmarks (SmartSQL, ORM-benchmark or TechEmpower) have historically placed it low in terms of performance. Lean object-to-database mappers like Dapper have consistently outperformed EF in query performance, but every new release of Microsoft's library has been closing the gap.
EF Core 6, the current released version, received performance improvements for non-tracking queries that brought the response times close to Dapper. According to TechEmpower, a development company that runs open-source benchmarks for web frameworks, the database mapper performance for EF has been improving over time, while still beyond ADO.NET, the legacy framework for database mapping in .NET Framework.
In the test run in June 2018, EF Core 2.1 reached 56% of raw ADO.NET performance on a Postgres database, while Dapper reached 72.1%.
In June 2022, EF Core 6 reaches parity with Dapper, both achieving 73% of raw ADO.NET performance.
EF Core 7 claims to bring similar improvements when saving to the database. EF maps the changes made to the objects in memory and translates them into SQL UPDATE statements when application code calls the SaveChanges method. Developer comments on a Reddit thread about Dapper versus EF highlight that the automatic detection of the tables to update is one of the biggest advantages when using EF.
According to Shay Rojansky, principal software engineer working on EF:
In EF7, SaveChanges performance has been significantly improved, with a special focus on removing unneeded network round trips to your database. In some scenarios, we’re seeing a 74% reduction in time taken – that’s a four-fold improvement!
The changes done in EF Core 7 are focused on reducing the number of network round trips to the database server and on optimising the generated SQL statements that are sent to the database in three code changes: one specifically for SQL Server and two generally applicable ones.
When there is a single update statement, EF Core 7 doesn’t use database transactions at all. This behaviour saves two round trips to the database.
There is an optimisation tailored for SQL Server when EF inserts multiple rows. EF7 doesn’t use a temporary table to retrieve database-generated keys with an OUTPUT clause. This saves a round trip but the OUTPUT clause can’t be used on a table with attached triggers without using a temporary table. While earlier versions of EF used OUTPUT with a temporary table, Microsoft decided to roll out the improved behaviour as a default in EF7, while providing a helpful exception that informs the developers how to opt out of the feature when it detects a table with triggers.
The last optimisation is about inserting dependent entities together. Until now, EF would generate two INSERT statements: the first one for the parent entity and the second one for the child entity. Usually, the key of the related parent entity would be known only after the first insertion has finished. When using identifiers that are possible to create on the client side, such as GUIDs, EF7 supplies them and combines the two INSERT clauses in one command execution, saving a round trip. Microsoft mentions that a similar performance benefit is available for integer identity keys, when using the HiLo feature of EF.
EF7 will be available for .NET Framework 6 and beyond. It will not be compatible with the legacy Windows .NET Framework. For those willing to give it a try already, there is a preview-build NuGet package available.