Entity Framework Core continues to make progress towards catching up with the original Entity Framework. First up is support for views. As surprising as it sounds, prior to the upcoming EF Core 2.1, database views were not officially supported. Nor was the rare table without a primary key.

There is a work-around in EF Core 2.0 for the lack of view support: you can declare a view as if it were a table, using the ROW_NUMBER to create a surrogate primary key. With that in place, you can then configure the database context as if the view were a table. If you can't modify the view to return a ROW_NUMBER, and no combination of columns is unique, you can mark a random column with the Key attribute. Then use AsNoTracking to avoid EF's caching logic, which would otherwise discard "duplicate" rows.

In EF Core 2.1, you can instead set the "query type" for the view, heap table, or inline SQL to "read-only". This will remove the need for a primary key.

Group By Support

Another unexpected limitation of EF Core is its inability to generate GROUP BY operations in SQL. Currently the whole dataset is transferred to the client, after which EF Core will perform the grouping operations in memory. This can cause significantly higher network, memory, and CPU utilization when compared to performing these operations in the database.

Until EF Core 2.1 is released, the workaround is to perform the grouping operation in a view or inline SQL. You can then use the workaround described above to treat the view as a table.

Lazy Loading

The hotly debated feature known as lazy loading. While some developers love it, others see it as full of pitfalls that can lead to poor performance or unexpected runtime failures. EF Core 2.1 adds lazy loading, but not like we saw in the original Entity Framework.

To enable lazy loading, the object must include a constructor that accepts an Action<object, string>. The collection properties are then written using this pattern:

public ICollection<Post> Posts { get => _lazyLoader.Load(this, ref _posts); set => _posts = value; }

In this example, _lazyLoader is the aforementioned Action object from the constructor. Load is an extension method that calls back into EF Core.

Like the original version of EF, future versions of EF Core are expected to support lazy loading without this boilerplate code.

Transactions

While transactions were always supported in EF Core, they were limited to just database transactions. In the next version you will be able to take advantage of TransactionScope and other capabilities offered by the System.Transactions namespace. Known as "ambient transactions", this allows for coordinating transactions across multiple resources including databases, message queues, web services, and the file system. For example, you can cause a database change to automatically rollback if a write to a transactions NTFS hard drive fails.

Value Conversions

An often underestimated feature of ORMs is the ability to support value conversions. In the simple case this deals with things such as storing enums as their underlying integer value or string representations. But things get more interesting when your ORM needs to support multiple database engines.

For example, say you have an unsigned integer in your data model. Some databases natively support unsigned integers, so you are good with those. However, others such as SQL Server only support signed integers. If your model needs to support both, having an ORM handle the conversion is important.

EF Core 2.1 plans to go even further and allow you to plug in custom conversion logic. This would, for example, allow transparent encryption and decryption of property values.

Spatial Data Types

The first response to the new roadmap was a renewed call for Spatial Data Type support. In SQL Server this is represented by the Geometry and Geography types. The difference being Geometry deals with Euclidean (flat) coordinate system while Geography handles the far more complex ellipsoidal coordinate systems.

This is partially supported in EF Core 2.1. First, you need to be running on top of .NET Framework. The libraries you need aren't available on .NET Core. Second, you need to use a view or inline SQL to convert the geometry and geography data into either well-known binary (WKB) or well-known text (WKT). These are industry standards for representing such data. Finally, you can write a value converter (as described above) to translate between WKB/WKT and the appropriate .NET objects.

You can see the other features planned for .NET Core in the EF 2.1 roadmap press release.