Announcing Entity Framework Core 2.1

Diego Vega

Today we are excited to announce the release of Entity Framework (EF) Core 2.1. This is the latest production-ready release of our open-source and cross-platform data access technology. We are releasing today alongside .NET Core 2.1 and ASP.NET Core 2.1. EF Core 2.1 targets .NET Standard 2.0 and so also runs on .NET Core 2.0 and .NET Framework 4.6.1 or later.

New features

More than 500 bug fixes and enhancements have been made since EF Core 2.0 was released. Because EF Core is developed as an open-source project on GitHub, a complete list of these changes can be found in the GitHub issue tracker:

The following sections highlight some of the most significant new features.

Lazy loading

EF Core now contains the necessary building blocks for anyone to author entity classes that can load their navigation properties on demand. We have also created a new package, Microsoft.EntityFrameworkCore.Proxies, that leverages those building blocks to produce lazy loading proxy classes based on minimally modified entity classes (e.g. classes with virtual navigation properties).

Read the documentation on lazy loading for more information about this topic.

Parameters in entity constructors

As one of the required building blocks for lazy loading, we enabled the creation of entities that take parameters in their constructors. You can use parameters to inject property values, lazy loading delegates, and services.

Read the documentation on entity constructors with parameters for more information about this topic.

Value conversions

Until now, EF Core could only map properties of types natively supported by the underlying database provider. Values were copied back and forth between columns and properties without any transformation. Starting with EF Core 2.1, value conversions can be applied to transform the values obtained from columns before they are applied to properties, and vice versa. We have a number of conversions that can be applied by convention as necessary, as well as an explicit configuration API that allows registering custom conversions between columns and properties. Some of the application of this feature are:

  • Storing enums as strings
  • Mapping unsigned integers with SQL Server
  • Automatic encryption and decryption of property values

There are currently some known limitations with value conversions:

  • Support is currently very limited for store-generated values (such as Identity columns) when a value converter is configured on the property. See issue #11597
  • Some query translations may not be performed correctly if a normally translated type (such as DateTime) is converted to a different type in the database. In such cases it may be necessary to force in-memory evaluation of the query. See issue #10265.

Read the documentation on value conversions for more information about this topic.

LINQ GroupBy translation

Before version 2.1, in EF Core the GroupBy LINQ operator was always be evaluated in memory. We now support translating it to the SQL GROUP BY clause in most common cases.

This example shows a query with GroupBy used to compute various aggregate functions:

var query = context.Orders
    .GroupBy(o => new { o.CustomerId, o.EmployeeId })
    .Select(g => new
        {
          g.Key.CustomerId,
          g.Key.EmployeeId,
          Sum = g.Sum(o => o.Amount),
          Min = g.Min(o => o.Amount),
          Max = g.Max(o => o.Amount),
          Avg = g.Average(o => Amount)
        });

The corresponding SQL translation looks like this:

SELECT [o].[CustomerId], [o].[EmployeeId],
    SUM([o].[Amount]), MIN([o].[Amount]), MAX([o].[Amount]), AVG([o].[Amount])
FROM [Orders] AS [o]
GROUP BY [o].[CustomerId], [o].[EmployeeId];

Note that some queries that compose GroupBy with other LINQ operators and query shapes may still be evaluated in memory. Also, there are some edge cases that now have issues where GroupBy was previously evaluated in memory. See the GitHub issue tracker for currently open issues involving GroupBy.

Data Seeding

With the new release it will be possible to provide initial data to populate a database. Unlike in EF6, seeding data is associated to an entity type as part of the model configuration. Then EF Core migrations can automatically compute what insert, update or delete operations need to be applied when upgrading the database to a new version of the model.

As an example, you can use this to configure seed data for a Post in OnModelCreating:

modelBuilder.Entity<Post>().HasData(new Post{ Id = 1, Text = "Hello World!" });

Read the documentation on data seeding for more information about this topic.

Query types

An EF Core model can now include query types. Unlike entity types, query types do not have keys defined on them and cannot be inserted, deleted or updated (i.e. they are read-only), but they can be returned directly by queries. Some of the usage scenarios for query types are:

  • Mapping to views without primary keys
  • Mapping to tables without primary keys
  • Mapping to queries defined in the model
  • Serving as the return type for FromSql() queries

Read the documentation on query types for more information about this topic.

Include for derived types

It will be now possible to specify navigation properties only defined on derived types when writing expressions for the Include method. For the strongly typed version of Include, we support using either an explicit cast or the as operator. We also now support referencing the names of navigation property defined on derived types in the string version of Include:

var option1 = context.People.Include(p => ((Student)p).School);
var option2 = context.People.Include(p => (p as Student).School);
var option3 = context.People.Include("School");

System.Transactions support

We have added the ability to work with System.Transactions features such as TransactionScope. This will work on both .NET Framework and .NET Core when using database providers that support it.

Read the documentation on System.Transactions for more information about this topic.

Better column ordering in initial migration

Based on customer feedback, we have updated migrations to initially generate columns for tables in the same order as properties are declared in classes. Note that EF Core cannot change order when new members are added after the initial table creation.

Optimization of correlated sub-queries

We have improved our query translation to avoid executing “N + 1” SQL queries in many common scenarios in which the use of a navigation property in the projection leads to joining data from the root query with data from a correlated sub-query. The optimization requires buffering the results form the sub-query, and we require that you modify the query to opt-in the new behavior.

As an example, the following query normally gets translated into one query for Customers, plus N (where “N” is the number of customers returned) separate queries for Orders:

var query = context.Customers.Select(
    c => c.Orders.Where(o => o.Amount  > 100).Select(o => o.Amount));

By including ToList() in the right place, you indicate that buffering is appropriate for the Orders, which enable the optimization:

var query = context.Customers.Select(
    c => c.Orders.Where(o => o.Amount  > 100).Select(o => o.Amount).ToList());

Note that this query will be translated to only two SQL queries: One for Customers and the next one for Orders.

OwnedAttribute

It is now possible to configure owned entity types by simply annotating the type with [Owned] and then making sure the owner entity is added to the model:

[Owned]
public class StreetAddress
{
    public string Street { get; set; }
    public string City { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public StreetAddress ShippingAddress { get; set; }
}

The new attribute is defined in a new package: Microsoft.EntityFrameworkCore.Abstractions. This package contains attributes and interfaces that you can use in your projects to light up EF Core features without taking a dependency on EF Core as a whole.

Read the documentation on owned entity types for more information about this topic.

EF commands in the SDK

The dotnet-ef commands now ship as part of the .NET Core SDK, so it will no longer be necessary to use DotNetCliToolReference in the project to be able to use migrations or to scaffold a DbContext from an existing database.

Note that these new commands support EF Core 2.0 and 2.1. These commands do not support EF Core 1.0 and 1.1. Instead a global.json file should be used to pin an earlier SDK and the DotNetCliToolReference to the old tools must be retained.

State change events

New Tracked And StateChanged events on ChangeTracker can be used to write logic that reacts to entities entering the DbContext or changing their state.

FromSql code analyzer

A new code analyzer is included with EF Core that detects possibly unsafe usages of our raw-SQL APIs (for example, FromSql) in which SQL parameters are not generated.

Obtaining the bits

The new bits are available in NuGet as individual packages, as part of the ASP.NET Core 2.1 meta-package and in the .NET Core 2.1 SDK, also released today.

The recommended way to obtain the new packages for ASP.NET Core applications is through installation of the new SDK. See the details in the Getting started section of the ASP.NET Core blog post.

For other types of application, either the SDK can be installed or the packages can be updated using the dotnet command line tool or NuGet.

Database provider

EF Core also requires a database provider for the database system you wish to use. The database providers for Microsoft SQL Server and the in-memory database are included in the ASP.NET Core meta-package. For other providers and for non-ASP.NET applications, the provider should be installed from a NuGet package. For example, using dotnet on the command-line:

$ dotnet add package Microsoft.EntityFrameworkCore.Sqlite

It is recommended that you also add a direct reference to the relational provider package to help ensure that you get all the newest EF Core bits. For example:

$ dotnet add package Microsoft.EntityFrameworkCore.Relational

When updating packages, make sure that all EF Core packages are updated to the 2.1.0 version. Mixing EF Core or infrastructure packages from older .NET Core versions (including previous 2.1 preview/rc bits) will likely cause errors.

Provider compatibility

As we mentioned in previous announcements, some of the new features in 2.1, such as value conversions, require an updated database provider. However, it was our original goal that existing providers developed for EF Core 2.0 would be compatible with EF Core 2.1 as long as you didn’t try to use the new features.

In practice, testing has shown that some of the EF Core 2.0 providers are not going to be compatible with 2.1. Also, there have been changes in the code necessary to support the new features since Preview 1 and Preview 2. Therefore, we recommend that you use a provider that has been updated for EF Core 2.1.

We have news that some of these updated providers will be available within days of this announcement. Others may take longer.

We have been working and will continue to work with provider writers to make sure we identify and address any issues with the upgrade. In the particular case of Pomelo.EntityFrameworkCore.MySql, we are actively working with the developers to help them get it ready for 2.1.

If you experience any new incompatibility, please report it by creating an issue in our GitHub repository.

Thank you!

As always, the entire Entity Framework team wants to express our deep gratitude to everyone who has helped in making this release better by trying early builds, providing feedback, reporting bugs, and contributing code.

Please try EF Core 2.1, and keep posting any new feedback to our issue tracker!

0 comments

Discussion is closed.

Feedback usabilla icon