Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ


Choose your language

InfoQ Homepage Articles Deep Diving into EF Core: Q&A with Jeremy Likness

Deep Diving into EF Core: Q&A with Jeremy Likness

Key Takeaways

  • Entity Framework (EF) Core is a cross-platform, extensible, open-source object-database mapper for .NET that supports most of the major databases developers use today.
  • EF Core is designed with the philosophy of making database development as easy as possible without compromising flexibility.
  • EF Core development is very much community-driven, and all of its releases feature community-initiated pull requests. 
  • The high-level plan for EF Core 6.0 is based on the most requested features, and it includes support for temporal tables, compiled models, multiple performance improvements, and features aimed at database management for cloud-native and distributed applications.
  • In its current version, EF Core is already the go-to solution for most lines of business .NET apps that work with a relational database.

Entity Framework (EF) Core is a cross-platform, extensible, open-source object-database mapper for .NET. Its first release was in 2016,  coinciding with the first versions of .NET Core and ASP.NET Core - one of Microsoft’s most important steps in bringing .NET to the open-source world. Since then, EF Core evolved alongside .NET Core until reaching its current form: a powerful and lightweight .NET ORM. 

InfoQ interviewed Jeremy Likness, program manager for .NET Data at Microsoft, to understand more about EF Core and what we should expect for its next release later this year.

InfoQ: Could you tell us a little bit about EF Core and how it’s been evolving since the first .NET Core Release?  

Jeremy Likness: EF Core is a cross-platform object “relational” mapper for .NET that supports most of the major databases developers use today, from SQL Server and SQLite to MySQL, PostgreSQL, and even Azure Cosmos DB. It provides features to streamline backend development, such as translation of LINQ queries to the local database dialect, change and concurrency tracking, mutations (inserts, updates, and delete), and schema management. The product was originally released as Entity Framework and built for the .NET framework. The most current version of Entity Framework is 6 (referred to as EF6), and it runs on both the .NET Framework and .NET Core. The main goal was to provide a migration path for EF6 customers to .NET Core. The first version of EF Core was a rewrite to take advantage of the modern features of .NET, C#, and cloud-native apps. It intentionally did not have 100% parity with EF6, but that gap has been closing with each release. The current EF Core version delivers a high-performance experience and has mostly closed the feature gap with EF6. EF Core 5 delivered major features like many-to-many, table-per-type (TPT), and split includes. There are also features in EF Core that were not available in EF6, including property value conversions, shadow state properties, global query filters, and support for nullable reference types.

 InfoQ: How does EF Core work?  

Jeremy: EF Core is designed with the philosophy of making database development as easy as possible without compromising flexibility. For example, you can write a LINQ query for your app. If you’re unable to shape the query based on your needs or if you find that performance is an issue that can be addressed by tweaking the SQL, EF Core allows you to drop down to raw SQL. EF Core is built on a provider model. A core set of APIs provides features that span supported databases. These are augmented by providers that deliver a set of capabilities scoped to the target database. This model makes it possible to extend EF Core to support other databases that are not “in the box.” The interface between the database, EF Core, and your custom code is the DbContext. The DbContext accepts runtime configuration so that it can be used in different environments and with different providers. It exposes a set of APIs to define what classes will be persisted in the database and configuring the model that defines the schema and mapping of the database entities to your local classes. The DbContext is implemented as a unit of work. It keeps track of entities during its lifetime through a change tracker. It is possible to manipulate several entities and apply the changes with a single operation that also handles concurrency. 

In my opinion, the best way to get familiar with how EF Core operates is to use a combination of logging and debug views. Logging in EF Core 5 was simplified to provide the option of configuring a target with a single statement. You can use the simple logging “LogTo” feature to direct logs to any method that accepts a string, including the console. The default logs are incredibly verbose and provide details about everything from how the DbContext is configured and what models are built to the database commands EF Core issues, including generated SQL. It is possible to filter the logging by severity and category. For example, you might suppress everything but raw SQL. Debug views are special classes in EF Core that provide detailed information about the service they are associated with. For example, the debug view of a LINQ query includes the summary of the expression tree and the SQL that will be generated from the LINQ. The debug view of the change tracker shows its internal state, including what entities are modified or marked for deletion and their key values. 

To me, the most fascinating area is the code that translates LINQ queries. It parses the expression tree that represents the query and translates it to SQL. It’s smart enough to take certain local functions such as string manipulations and translate them to their database counterparts and warn when an expression isn’t supported or translatable. The query pipeline doesn’t stop at generating the query but must also be able to parse the results and materialize them based on the original LINQ, which may have used projections to shape the data using anonymous types. EF Core supports multiple CLR types for an entity, so it is possible, for example, to project a result to a dictionary and pass data around as property bags instead of using a specific class.

InfoQ: Microsoft adopted a community-driven feature release for .NET 6. Is it the same for EF Core? If so, what are the most requested features for the upcoming release? 

Jeremy: EF Core is very much community-driven, and all our releases feature community-initiated pull requests. We do our planning in the open, publish our roadmap and provide regular updates. The high-level plan for EF Core 6.0 is based on the most requested features and is available here. Those features include: 

  • Support for temporal (“point in time”) tables.
  • A common mechanism for working with JSON columns across different providers.
  • Compiled models to improve startup performance.
  • Match Dapper for performance based on the TechEmpower benchmark (specifically the Fortunes benchmark).
  • Updates to the query engine to achieve 100% parity with EF6.
  • Improvements to migrations to make it easier to manage databases in cloud-native and distributed applications.

You can track our progress (broken down per preview release) by reading “What’s new in EF Core 6.0”. 

InfoQ: Performance seems to be a recurring theme in all releases expected for this year. Is this something we can expect for EF Core 6 as well?  

Jeremy: Absolutely! We set the very aggressive goal of meeting Dapper’s performance based on the Fortunes benchmark. This is aggressive because Dapper is a lightweight tool optimized for fast queries and is often labeled a “Micro ORM”. EF Core intentionally takes on additional overhead to improve the development experience. For example, unlike Dapper, EF Core allows you to write queries using LINQ. This gets rid of strings that aren’t easy to refactor and provides strong typing for development and compile-time validation. Although many of our customers use both EF Core and Dapper in the same application, it would be nice to give them the option of not having to take on another dependency if the only reason they use Dapper is for query performance. The team has been hard at work making various performance optimizations, and I’m excited to report as of the last status update (you can follow them online here) on April 22nd, the EF Core 6 TechEmpower Fortunes benchmark is 33% faster than EF Core 5 and is 93% of Dapper performance. The gap has narrowed substantially, and we are optimistic that we will improve performance even more before EF Core 6 is released. On the other hand, the Dapper team continues to improve their performance, so we’re chasing a moving target. Of course, performance improvements in both products benefit everyone in the ecosystem, so this a race we’re more than happy to come in a close second.

InfoQ: It’s been a few months since EF Core 5 has been released (Nov/2020). How’s it been received by .NET developers? 

Jeremy: I’ve received overwhelmingly positive feedback. EF Core 5 included several highly requested features, including many-to-many, table-per-type, and split query. A common theme I hear when speaking with developers is “I was frustrated that EF Core didn’t support <insert feature here> but that’s been addressed in EF Core 5.” I’ve shared demos of the new capabilities at several virtual meetups and conferences and had positive feedback. Having said that, I’m always looking for feedback to better understand ways we can improve the product. I encourage developers reading this who are using EF Core to reach out to me on GitHub or Twitter to share their experience. The developers I’ve spoken to so far have shared that the migration to EF Core 5 was straightforward, and they see immediate performance benefits along with the new features. If that hasn’t been your experience, let us know so we can address it - whether it’s through a code change, pointing to the right information, or updating our documentation to be more clear.

InfoQ: According to the official documentation, EF Core 6.0 will align with .NET 6 as a long-term support (LTS) release. Considering the breaking changes from EF Core 5, should new adopters start using EF Core 5 now (and migrate later), or should they start planning their adoption using the EF Core 6 previews?

Jeremy: The EF Core team is committed to minimizing breaking changes and making the upgrade path as seamless as possible. We document all breaking changes for each release. Even our nightly builds undergo the same level of quality control and rigorous testing as our final releases. Our recommendation is to use the latest version that supports the features you need. EF Core 5 has so many important features that I can’t think of a reason not to adopt it. I also encourage early adoption of the previews when possible. This not only gives you access to the latest features and performance improvements but also gives us the opportunity to address any issues that may come up before the final release. As we state in our status updates, “the sooner we get such feedback, the more likely it will be actionable before the next official release.”

InfoQ: In which scenarios would you recommend the adoption of EF Core?

Jeremy: I’m obviously biased, but I believe EF Core is the go-to solution for most line of business .NET apps that work with a relational database. It is incredibly easy to get started but offers advanced capabilities such as migrations, changes tracking, and concurrency detection that become essential for larger applications. For the most part, the performance overhead is minimal and a more than acceptable trade-off to move from raw SQL and string manipulation to a strongly typed programming model. There are a few exceptions. Although we are aggressively tackling performance across all supported platforms, there is still work to be done on the mobile side due to how EF Core is optimized and constraints in the app model. There are benefits to using it with mobile, but I would test performance early on and compare it with mobile-specific solutions like Sqlite.NET. Blazor WebAssembly apps don’t have direct access to most database ports and protocols, so it doesn’t make sense to use it there (except on the server). If your app is mostly read-only and doesn’t provide a full suite of create/read/update/delete (CRUD) operations, Dapper may be a more suitable solution.

There is a gray area if you are targeting Azure Cosmos DB. Our provider has all the basic capabilities built-in but does not support all the features that exist in the native SDK. We document all limitations related to Cosmos here. The provider makes it very easy to get up and running, so I do recommend it if you aren’t impacted by the limitations. It is especially useful if your development team is already familiar with EF Core, and for scenarios that involve multiple backends. For example, a team at Microsoft has an Azure Function that ingests data and fans it out to both SQL Server and Azure Cosmos DB. They use EF Core to reuse the same DbContext to push changes to both databases. If you need more advanced capabilities, explore the native SDK, and please either file an issue or upvote an existing issue so that we can prioritize the right features for future releases.

InfoQ: Where can our readers start learning about EF Core and how to use it in their projects?

Jeremy: The team works continuously to improve and keep our official documentation up to date. If you start from our main landing page you’ll find a set of “cards” to help guide your journey. The “develop your first app” card links to walkthroughs for different platforms, including web apps, WPF, and Xamarin. There is a card for databases and one for platforms. The level ranges from introductory like our “Get Started with EF Core” article to advanced documentation like the change tracking debugging page. We want this to be the gold standard for understanding EF Core, so if a reader finds something is missing, we want them to file an issue so it can be addressed. If you learn more by watching videos, we host an EF Core Community Standup every other week and cover a variety of data-related topics, including deep dives and demos of EF Core. You can access recordings of past standups.

About the Interviewee 

Jeremy Likness is a program manager for .NET Data at Microsoft. Jeremy began writing code at a young age and has been a professional developer in some capacity for almost three decades. Jeremy is a published author and international speaker with the personal mission to empower developers to be their best. At Microsoft, he fulfills this mission by helping provide the best possible experience of working with data for .NET developers. Jeremy’s hobbies include hiking, astrophotography, and virtual reality. Jeremy was diagnosed with Young Onset Parkinson’s Disease in February of 2020 and hosts the “You, Me, and PD” podcast with his wife to raise awareness. You can follow Jeremy on Twitter and his technology blog.





Rate this Article