This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Download Microsoft Edge
More info about Internet Explorer and Microsoft Edge
Besides numerous bug fixes and small functional and performance enhancements, EF Core 2.1 includes some compelling 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 (for example, classes with virtual navigation properties).
Read the
section 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
section on entity constructor 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
Read the
section on value conversions
for more information about this topic.
LINQ GroupBy translation
Before version 2.1, in EF Core the GroupBy LINQ operator would 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 => 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];
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 section 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 (that is, 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 section 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");
Read the section on Include with derived types for more information about this topic.
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 section 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.
We have improved our query translation to avoid executing "N + 1" SQL queries in many common scenarios in which the usage of a navigation property in the projection leads to joining data from the root query with data from a correlated subquery. The optimization requires buffering the results from the subquery, 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.
[Owned] attribute
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 dotnet-ef commands are now part of the .NET Core SDK, therefore 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.
See the section on installing the tools for more details on how to enable command line tools for different versions of the .NET Core SDK and EF Core.
Microsoft.EntityFrameworkCore.Abstractions package
The new 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. For example, the [Owned] attribute and the ILazyLoader interface are located here.
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.
Raw SQL parameter analyzer
A new code analyzer is included with EF Core that detects potentially unsafe usages of our raw-SQL APIs, like FromSql
or ExecuteSqlCommand
. For example, for the following query, you will see a warning because minAge is not parameterized:
var sql = $"SELECT * FROM People WHERE Age > {minAge}";
var query = context.People.FromSql(sql);
Database provider compatibility
It is recommended that you use EF Core 2.1 with providers that have been updated or at least tested to work with EF Core 2.1.
If you find any unexpected incompatibility or any issue in the new features, or if you have feedback on them, please report it using our issue tracker.