The past, present and future of EF Core
Entity Framework 1 was introduced back in 2008 with .NET 3.5 Service Pack 1. During the same time, LINQ to SQL also came out, but Microsoft didn’t consider it to be an Object-Relational Mapper (O/RM). Unlike Entity Framework, LINQ to SQL was only meant to support SQL Server.
Are you keeping up with new developer technologies? Advance your IT career with our Free Developer magazines covering C#, Patterns, .NET Core, MVC, Azure, Angular, React, and more. Subscribe to the DotNetCurry (DNC) Magazine for FREE and download all previous, current and upcoming editions.
It featured both LINQ, a brand new toy back then – and something called Entity-SQL, an object-oriented SQL-alike dialect that never really caught up. It had features like multiple inheritance strategies, compiled queries, explicit loading, change tracking and other features that are commonly expected from an ORM. It was based on a provider model, so in theory it was able to support any relational database for which there was an ADO.NET Provider. Visual Studio could reverse-engineer a database and produce a model for it.
However it was received with mixed feelings.
On one end, it was good to see Microsoft having a go at ORM, but there were already other products that could do the same and more. NHibernate had been around for some time and was quite popular back then.
The problems with LINQ to SQL were:
- Although it was touted that it supported other databases, it really only worked well with SQL Server
- It was complex to configure in Visual Studio – let alone XML configuration
- Entities had to inherit from a base class
- The generated SQL was far from optimal
Some developers even issued a vote of no confidence (http://efvote.wufoo.com/forms/ado-net-entity-framework-vote-of-no-confidence) to show how bad they felt about it.
The second version, now bumped to v4 to align with the release of .NET 4 in 2010 improved it a bit – with self-tracking entities with an eye for WCF, lazy loading, initial support for Plain-Old CLR Objects (POCOs), but people were still unsatisfied, even though it was then Microsoft’s recommended database access technology.
It was only with version 4.1, popularly known as Code First, which happened in 2011, that things started to look interesting.
Entity Framework went through a big refactor, it seemed much more polished and clean, fully embracing POCOs and was code-centric.
It was now much easier to start working with. Almost no mapping and configuration was required as it was based on conventions – things just worked out of the box. The version was somewhat misleading, as it seemed to be a whole new version, but underneath, the “old” Entity Framework was still there.
Another version 4.3, came out shortly which featured migrations, a welcome addition, but not one without its problems.
Then came version 5, bringing support for enumerated and spatial types and table-valued functions, and was released in the same year, 2012.
Finally, version 6 brought most of the stuff that mature ORMs support, such as interceptors, logging capabilities, custom conventions, support for stored procedures and asynchronous methods.
Life was good in 2013!
But then Microsoft started working on something new, and this had a profound impact on Entity Framework.
Enter .NET Core!
Entity Framework Core
.NET Core was in the forge for several years, and it’s not hard to understand why.
Put it simply, Microsoft wanted to rewrite its framework from scratch, make it open-source and support operating systems other than Windows – not something to be taken lightly!
Of course, Entity Framework had to be re-implemented as well, and Microsoft took the opportunity to do things right this time.
EF Core, as it is now called, was totally rewritten, but tried to stay close to Code First.
Because it was a massive task, a roadmap was defined for its features, but from the start, a couple of them were received with lot of interest:
- It would work on all operating systems (Linux, Mac) and platforms (Windows Phone, Windows Store) supported by .NET Core
- Non-relational databases would also be supported, making it not just an ORM: Azure Table Storage and Redis were the first to be announced
- Fully extensible and provider-based
The Entity Framework Core team reunites regularly and makes available a summary of their decisions. Interested folks can submit issues and participate in the discussions, but of course, the last word belongs to Microsoft.
EF Core 1 was eventually released in 2016, followed by version 1.1 the same year, but it was far from what was expected.
EF Core – The good bits
The good about it was:
- Brand new code base, with most types public and following best practices, all available in GitHub
- It did work on operating systems other than Windows and on platforms other than PCs
- Almost infinitely extensible
- Support for providers other than SQL Server (SQL Server Compact Edition, SQLite, InMemory, PostgreSQL, MySQL, DB2, MyCat, Oracle)
- A simplified API that is close to the previous one (Code First)
- New features: shadow properties, ability to mix SQL with LINQ, transparent client-side function evaluation, high-low identifier generation, batching of queries, improved SQL generation
EF Core v2.0 has just been released and it brought along other interesting features, chief among them are global queries (very handy for multi-tenant and soft-deletes), owned types (complex values) and a limited form of support for database functions.
To summarize, EF Core 2 is pleasant to use. It’s easy to get started with.
The shortcoming needs some explaining.
EF Core 2.0 - Shortcomings
1. One of the more appealing new features was the ability to target non-relational databases.
It seems like a great idea – just use the same APIs and LINQ to work with potentially any kind of data source imaginable.
The problem is, this is yet to be seen, as no such provider was actually released – if you don’t consider InMemory of course! The code is nowhere to be found on GitHub and we have no idea of what it will be like, when (if?) it is actually released.
2. Microsoft boasts about improvements in the SQL generation in EF Core, but a crucial feature such as support for grouping (LINQ’s GroupBy operator) is not supported yet – or worse, it does not fail, yet silently does it all in memory, with possibly a tremendous impact on performance.
Unaware developers may have a bad time with this, and there is no easy solution to it, essentially because it is not possible to project to non-entity classes yet.
3. Worse, it is not possible to perform date and time operations with LINQ, and lots of SQL standard mathematical operators are also missing. Version 2 brought support for LIKE, but that’s it.
4. Lazy loading is a feature that people are expected to use, but alas, it is not here. Version 1.1 brought explicit loading, and eager loading was here since version 1, but it’s still surprisingly absent.
5. No many-to-many collections and no inheritance strategies, only single table inheritance.
6. Migrations are here already, but a missing feature is database initializers or the capability to seed the database. We have to rely on custom SQL for that, which is at least cumbersome, when we’re talking about an ORM.
7. No interception capabilities exist yet, meaning, it’s very difficult to modify a query before it is actually executed. No out of the box way to delegate entity creation and initialization.
8. The ability to use stored procedures for Create-Update-Delete (CUD) operations is also not yet implemented. It is possible to use stored procedures for querying, though.
9. It is not possible yet to plug our own custom conventions.
10. Spatial types are absent too, but enumerations and complex types are now supported.
11. Also, no support for System.Transactions (aka, TransactionScope) and distributed transactions. I guess we can understand that since the first steps were to get this running on Linux and Mac, for which there is no Microsoft Distributed Transaction Coordinator (MS DTC), this is a feature that people are used to.
12. Finally, still no Visual Studio (VS) integration. It is not possible to reverse-engineer a database from inside VS or to apply database migrations, except of course, using Package Manager.
From what I mentioned, it should be clear that EF Core is not ready for enterprise-level usage, in fact, Microsoft even says that on the Roadmap page.
It is obvious that EF Core is new and Microsoft hasn’t had the time to implement everything, but some of the absences – grouping, date/time and mathematical operations, lazy loading – are hard to understand.
Also, developers had shown a deep interest for non-relational providers and these are conspicuously absent.
Alternatives to EF Core
There are few full-featured ORMs that can work with .NET Core, one of which is LLBLGen Pro, but it is a commercial product.
NHibernate still does not target .NET Core or .NET Standard, and by the looks of things, it will take a long time until it does. Dapper, the micro-ORM, is already available for .NET Core, but it is not a full-featured product. Clearly, there is no free cross-platform alternative to EF Core yet, so with all its shortcomings, it’s probably your best option for now.
If we are to compare Entity Framework Core vCurrent with another well-established O/RM, NHibernate, we can see that EF is still behind in a number of features including:
- Lots of identifier generation strategies
- Different collection types, including collections of primitive types
- Database-independent dialect for querying and doing batch updates (HQL)
- Support for non-trivial mapping scenarios
- Lazy properties
- Type conversions
The problem with NHibernate currently seems to be the lack of interest from the community, even if some of its features are still ahead of its competitors.
The Entity Framework Core Roadmap page (https://github.com/aspnet/EntityFrameworkCore/wiki/Roadmap) details what are the features that will be implemented in the next version, 2.1.
We can see that some of the missing features I highlighted – grouping, lazy loading (probably), System.Transactions, lifecycle events – are already there/planned, plus a few others like support for Oracle and Cosmos DB.
It is possible that things are going in the right direction. There are however some features, like mapping strategies, concrete table inheritance and class table inheritance, who don’t seem to be attracting a lot of interest from the community. So probably these will not be around for quite some time.
We, as developers, have a saying in this, however Microsoft this time seems to be listening to the community, so it’s our responsibility to bring our concerns to them, and contribute to their resolution.
Entity Framework Core is cool because it can run on any of the .NET Core supported platforms and it offers some interesting features over the previous, pre-Core, versions.
It is quite new, so it is still lacking lots of stuff, but since the community is helping, these features may actually be implemented sooner than one would think.
I think EF is getting interest from developers, although people were somewhat unhappy with the absence of some functionality that are deemed essential by some. For now, as there is no clear alternative for multi-platform work, you may want to give it a try.