Announcing Entity Framework Core 3.0 and Entity Framework 6.3 General Availability

Diego Vega

We are extremely excited to announce the general availability of EF Core 3.0and EF 6.3 on nuget.org.

The final versions of .NET Core 3.0 and ASP.NET Core 3.0 are also available now.

How to get EF Core 3.0

EF Core 3.0 is distributed exclusively as a set of NuGet packages. For example, to add the SQL Server provider to your project, you can use the following command using the dotnet tool:

dotnet add package Microsoft.EntityFrameworkCore.SqlServer --version 3.0.0

When upgrading applications that target older versions of ASP.NET Core to 3.0, you also have to add the EF Core packages as an explicit dependency.

Also starting in 3.0, the dotnet ef command-line tool is no longer included in the .NET Core SDK. Before you can execute EF Core migration or scaffolding commands, you’ll have to install this package as either a global or local tool. To install the final version of our 3.0.0 tool as a global tool, use the following command:

dotnet tool install --global dotnet-ef --version 3.0.0

Specifying the version in the command is now optional. If you omit it, dotnet tool install will automatically install the latest stable version, which is right now 3.0.0.

It’s possible to use this new version of dotnet ef with projects that use older versions of the EF Core runtime. However, older versions of the tool will not work with EF Core 3.0.

What’s new in EF Core 3.0

Including major features, minor enhancements, and bug fixes, EF Core 3.0 contains more than 600 product improvements. Here are some of the most important ones:

LINQ overhaul

We rearchitected our LINQ provider to enable translating more query patterns into SQL, generating efficient queries in more cases, and preventing inefficient queries from going undetected. The new LINQ provider is the foundation over which we’ll be able to offer new query capabilities and performance improvements in future releases, without breaking existing applications and data providers.

Restricted client evaluation

The most important design change has to do with how we handle LINQ expressions that cannot be converted to parameters or translated to SQL.

In previous versions, EF Core identified what portions of a query could be translated to SQL, and executed the rest of the query on the client. This type of client-side execution is desirable in some situations, but in many other cases it can result in inefficient queries.

For example, if EF Core 2.2 couldn’t translate a predicate in a Where() call, it executed an SQL statement without a filter, transferred all the rows from the database, and then filtered them in-memory:

var specialCustomers = 
  context.Customers
    .Where(c => c.Name.StartsWith(n) && IsSpecialCustomer(c));

That may be acceptable if the database contains a small number of rows but can result in significant performance issues or even application failure if the database contains a large number or rows.

In EF Core 3.0, we’ve restricted client evaluation to only happen on the top-level projection (essentially, the last call to Select()). When EF Core 3.0 detects expressions that can’t be translated anywhere else in the query, it throws a runtime exception.

To evaluate a predicate condition on the client as in the previous example, developers now need to explicitly switch evaluation of the query to LINQ to Objects:

var specialCustomers =
  context.Customers
    .Where(c => c.Name.StartsWith(n)) 
    .AsEnumerable() // switches to LINQ to Objects
    .Where(c => IsSpecialCustomer(c));

See the breaking changes documentation for more details about how this can affect existing applications.

Single SQL statement per LINQ query

Another aspect of the design that changed significantly in 3.0 is that we now always generate a single SQL statement per LINQ query. In previous versions, we used to generate multiple SQL statements in certain cases, like to translate Include() calls on collection navigation properties and to translate queries that followed certain patterns with subqueries. Although this was in some cases convenient, and for Include() it even helped avoid sending redundant data over the wire, the implementation was complex, it resulted in some extremely inefficient behaviors (N+1 queries), and there was situations in which the data returned across multiple queries could be inconsistent.

Similarly to client evaluation, if EF Core 3.0 can’t translate a LINQ query into a single SQL statement, it throws a runtime exception. But we made EF Core capable of translating many of the common patterns that used to generate multiple queries to a single query with JOINs.

Cosmos DB support

The Cosmos DB provider for EF Core enables developers familiar with the EF programing model to easily target Azure Cosmos DB as an application database. The goal is to make some of the advantages of Cosmos DB, like global distribution, “always on” availability, elastic scalability, and low latency, even more accessible to .NET developers. The provider enables most EF Core features, like automatic change tracking, LINQ, and value conversions, against the SQL API in Cosmos DB.

See the Cosmos DB provider documentation for more details.

C# 8.0 support

EF Core 3.0 takes advantage of a couple of the new features in C# 8.0:

Asynchronous streams

Asynchronous query results are now exposed using the new standard IAsyncEnumerable<T> interface and can be consumed using await foreach.

var orders = 
  from o in context.Orders
  where o.Status == OrderStatus.Pending
  select o;

await foreach(var o in orders.AsAsyncEnumerable())
{
  Process(o);
}

See the asynchronous streams in the C# documentation for more details.

Nullable reference types

When this new feature is enabled in your code, EF Core examines the nullability of reference type properties and applies it to corresponding columns and relationships in the database: properties of non-nullable references types are treated as if they had the [Required] data annotation attribute.

For example, in the following class, properties marked as of type string? will be configured as optional, whereas string will be configured as required:

public class Customer
{
  public int Id { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string? MiddleName { get; set; }
}

See nullable reference types in the C# documentation for more details.

Interception of database operations

The new interception API in EF Core 3.0 allows providing custom logic to be invoked automatically whenever low-level database operations occur as part of the normal operation of EF Core. For example, when opening connections, committing transactions, or executing commands.

Similarly to the interception features that existed in EF 6, interceptors allow you to intercept operations before or after they happen. When you intercept them before they happen, you are allowed to by-pass execution and supply alternate results from the interception logic.

For example, to manipulate command text, you can create an IDbCommandInterceptor:

public class HintCommandInterceptor : DbCommandInterceptor
{
  public override InterceptionResult ReaderExecuting(
    DbCommand command, 
    CommandEventData eventData, 
    InterceptionResult result)
  {
    // Manipulate the command text, etc. here...
    command.CommandText += " OPTION (OPTIMIZE FOR UNKNOWN)";
    return result;
  }
}

And register it with your DbContext:

services.AddDbContext(b => b
  .UseSqlServer(connectionString)
  .AddInterceptors(new HintCommandInterceptor()));

Reverse engineering of database views

Query types, which represent data that can be read from the database but not updated, have been renamed to keyless entity types. As they are an excellent fit for mapping database views in most scenarios, EF Core now automatically creates keyless entity types when reverse engineering database views.

For example, using the dotnet ef command-line tool you can type:

dotnet ef dbcontext scaffold "Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer

And the tool will now automatically scaffold types for views and tables without keys:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  modelBuilder.Entity<Names>(entity =>
  {
    entity.HasNoKey();
    entity.ToView("Names");
  });

  modelBuilder.Entity<Things>(entity =>
  {
    entity.HasNoKey();
  });
}

Dependent entities sharing a table with principal are now optional

Starting with EF Core 3.0, if OrderDetails is owned by Order or explicitly mapped to the same table, it will be possible to add an Order without an OrderDetails and all of the OrderDetails properties, except the primary key will be mapped to nullable columns.

When querying, EF Core will set OrderDetails to null if any of its required properties doesn’t have a value, or if it has no required properties besides the primary key and all properties are null.

public class Order
{
    public int Id { get; set; }
    public int CustomerId { get; set; }
    public OrderDetails Details { get; set; }
}

[Owned]
public class OrderDetails
{
    public int Id { get; set; }
    public string ShippingAddress { get; set; }
}

What’s new in EF 6.3

We understand that many existing applications use previous versions of EF, and that porting them to EF Core only to take advantage of .NET Core can require a significant effort. For that reason, we decided to port the newest version of EF 6 to run on .NET Core 3.0. The developer community also contributed to this release with several bug fixes and enhancements.

Here are some of the most notable improvements:

  • Support for .NET Core 3.0
    • The EF 6.3 runtime package now targets .NET Standard 2.1 in addition to .NET Framework 4.0 and 4.5.
    • This means that EF 6.3 is cross-platform and supported on other operating systems besides Windows, like Linux and macOS.
    • The migration commands have been rewritten to execute out of process and work with SDK-style projects.
  • Support for SQL Server hierarchyid
  • Improved compatibility with Roslyn and NuGet PackageReference
  • Added the ef6.exe utility for enabling, adding, scripting, and applying migrations from assemblies. This replaces migrate.exe

There are certain limitations when using EF 6.3 in .NET Core. For example:

  • Data providers need to be also ported to .NET Core. We only ported the SQL Server provider, which is included in the EF 6.3 package.
  • Spatial support won’t be enabled with SQL Server because the spatial types aren’t enabled to work with .NET Core.
    • Note that this limitation applies to EF 6.3 but not to EF Core 3.0. The latter continues to support spatial using the NetTopologySuite library.
  • There’s currently no support for using the EF designer directly on .NET Core or .NET Standard projects.

For more details on the EF 6.3 release, and a workaround to the latter limitation, see What’s new in EF 6.3 in the product’s documentation.

What’s next: EF Core 3.1

The EF team is now focused on the EF Core 3.1 release, which is planned for later this year, and on making sure that the documentation for EF Core 3.0 is complete.

EF Core 3.1 will be a long-term support (LTS) release, which means it will be supported for at least 3 years. Hence the focus is on stabilizing and fixing bugs rather than adding new features and risky changes. We recommend that you adopt .NET Core 3.0 today and then adopt 3.1 when it becomes available. There won’t be breaking changes between these two releases.

The full set of issues fixed in 3.1 can be seen in our issue tracker. Here are some worth mentioning:

  • Fixes and improvements for issues recently found in the Cosmos DB provider
  • Fixes and improvements for issues recently found in the new LINQ implementation
  • Lots of regressions tests added for issues verified as fixed in 3.0
  • Test stability improvements
  • Code cleanup

The first preview of EF Core 3.1 will be available very soon.

Thank you

If you either sent code contributions or feedback for any of our preview releases, thanks a lot! You helped make EF Core 3.0 and EF 6.3 significantly better!

We hope everyone will now enjoy the results.

57 comments

Discussion is closed. Login to edit/delete existing comments.

  • Kevin Trace 0

    Does Entity Framework 6.3 support Visual Studio 2015? I am getting the following error after upgrading:

    The default XML namespace of the project must be the MSBuild XML namespace. If the project is authored in the MSBuild 2003 format, please add xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″ to the element. If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format.

    • Brice LambsonMicrosoft employee 0

      I’ve filed issue #1292.

  • MATTIAS ENGMAN 0

    Ahh, very nice!! Ef 6 for .net core, the last piece in our full migration to net core.🥳 Thank you

  • Daniel Root 0

    Can you explain the value proposition of EF Core now that full EF is available in .NET Core? Is EF Core faster or better in any way? When do we choose EF Core vs EF Full?

    • Diego VegaMicrosoft employee 0

      It’s better in many ways (see https://docs.microsoft.com/ef/efcore-and-ef6/), usually faster, and a more manageable codebase for us to keep evolving and adding features and performance improvements to.

      • Daniel Root 0

        Thanks, that list is helpful. I’m old enough to remember LINQ-to-SQL vs EF and want to be sure I’m picking a path that will continue to be developed. It seems like at some point in the future one of these will need to give way to the other at least in the “done not dead” sense. Personally, “many-to-many without mapping entity” is biggest roadblock for moving some of our code to EF Core. It’s nice to have an option now, but I’d still rather see it in EF Core if it is faster/better in other measures.

      • Thomas Tomiczek 0

        If by better in many ways means it will stop compelx queries from wasting time in debugging BECAUSE IT DOES NOT WORK – yes. Totally.

        I am happy to now rip out EFCore and replace it with EF – that one actually works.

        I am not talking of bad API.

        * So far Global Queries was a “never use” scenario because with it sql deserialization would fail in certain scenarios (which appen often – Entity A having Foreign key to Entity B, and Entity B being filtered out by global query… not possible to materialize). That thank heaven is fixed in 3.0
        * For that, 3.0 makes query generation slow. If you use includes. Pre a hotfix after the last RC 7 includes could take minutes (no joke). Now this is better – jsut seconds. Still, a 5ms query may take 10 seconds generating the SQL, which means: NOT USABLE.

        Personally I am on holdiays now and once I Return I will either rip out EfCore OR upgrade to a nightly hoping that the November Release of 3.1 finally makes it usable. So far EF Core has been amazingly reluctant to get usable.

        Here is how bad it is. For every (!) LINQ Query I Run it through a set of analyzers. Depending on their result, I either execute the SQL in db, OR load all the data into memory and use LINQ to objects. NO JOKE. Otherwise I get too many SQL level errors. Yes, slow as molass and we need to replace it before production end of October. Now it looks like the bugs are gone – and the performance is now as slow as loading all data into memory.

        The concept is AMAZING. I wonder whether it will be usable before Version 6 😉

  • PandaSharp 0

    What about UWP support?

    • Thomas De Wulf 0

      Great question!!!!!!!!

      • Diego VegaMicrosoft employee 0

        UWP would need to support .NET Standard 2.1. I have tried to find out when/if this is going to happen, but didn’t get a definitive answer. I will try again.

  • Stilgar Naib 0

    How does EF Core know when to treat types as non-nullable? I mean what if I had switched off the null annotations in the project because I am not ready to migrate yet? Will string still be treated as non-nullable?

    • Diego VegaMicrosoft employee 0

      No, reference types will only be detected as non-nullable In code in which the C# feature is enabled.

  • Oğuz Karadenizli 0

    Time to write the nolock interceptor to EF core 🙂

    • Thomas De Wulf 0

      And ruin your ACID data integrity in the process 😉

    • Diego VegaMicrosoft employee 0

      In case you missed it, we showed an interceptor that added a query hint in our dotNETConf demo today. The advantage is that now you can use query tags to control the interceptor.

      https://youtu.be/PXdgyPpfaz4

    • Thomas Tomiczek 0

      You should never use that one.

      (readcommitted) at least makes sure the data has integrity and is way lighter on the locks, but nolock may return invalid data 😉

  • Mike M 0

    Can .NET Core 3.0 be used with EF Core 2.2? To reduce breaking changes?

    • Diego VegaMicrosoft employee 0

      We haven’t tested the combination, and it won’t be supported, but in theory things should work, unless it is an ASP.NET Core application, and there were breaking changes in the Microsoft.Extensions.* libraries (which I don’t know for a fact). See https://github.com/aspnet/EntityFrameworkCore/issues/16372 for a checklist we came up with, but then decided not to pursue.

      • Jon Miller 0

        So, in other words, you can’t have a library that is shared by .NET Framework 4.8 and .NET Core 3 that uses EF Core, because .NET Framework doesn’t support .NET Standard 2.1 which is required by EF Core 3, and .NET Core 3 doesn’t support running EF Core 2.x, which is the only thing that will work with .NET Framework.

  • Jon Miller 0

    What is your recommendation for Web Forms projects? I put a lot of time and effort into porting from EF 6 to EF Core. There have been a lot of problems with the query engine, missing features, etc. Now, after all that, I am stuck on an old version. Microsoft is just flat out wrong leaving Web Forms developers out in the cold. Blazor isn’t done and MVC never matched the functionality that Web Forms had when paired with something like Telerik’s rich UI components. If Microsoft doesn’t move Web Forms forward, or at least make it so that it can use the latest EF Core, I will have to say in retrospect that it was a total waste of time even bothering with EF Core. I would have been better of switching to Dapper way back when. I could have avoided numerous problems with the query engine, slow startup time, and would not be cut off now. I am not happy at all.

    • Daniel RothMicrosoft employee 0

      Hi Jon,

      Support for Blazor Server apps is now available with .NET Core 3.0. Can you share what things you feel are still missing from Blazor to call it “done”? I’m sure there are still many gaps!

      We are starting to look at how we can meet the needs of Web Forms developers better with Blazor. There’s much that’s similar between Web Forms and Blazor: event-driven, stateful components/controls, UI composition, etc. Blazor obviously isn’t Web Forms, so it doesn’t offer and a seamless migration path to .NET Core for existing Web Forms apps, but for new development we hope that Blazor will be an appealing option. Various component vendors are now offering Blazor components: Telerik, DevExpress, Syncfusion, Radzen. We’ve also started work on some content to try to help Web Forms devs make this transition: https://docs.microsoft.com/en-us/dotnet/architecture/blazor-for-web-forms-developers/. The book is still a work in progress, but I’d be really interested to get your thoughts on it.

      Obviously, none of this helps with not being able to use newer versions of EF Core on .NET Framework, but hopefully it starts to demonstrate that we do still care about Web Forms developers and we are looking for ways to help move them forward into the .NET Core world.

      • Jon Miller 0

        Daniel,

        I’m sure Blazor will be great when everything is said and done. However, some apps are just not going to be re-written from scratch. IMHO it is ridiculous that EF is being made so that it does not work with Web Forms. Furthermore, I totally disagree with the fact that you are not getting Web Forms working on .NET Core. Especially, when you even have Windows Forms working. If anything, Web Forms should have been an easier port. It looks to me that you are simply forcing people to completely re-write everything. People can tell me that I suck and that I shouldn’t be using Web Forms all they want. I have spent many years refining my apps and getting them to where they are solid and do exactly what I want. I won’t be re-writing them to a framework that isn’t mature and isn’t fully developed. Besides that, management will simply force me onto some other platform if I do, and it won’t be Microsoft. Furthermore, I cannot stand SPAs.

        • Yuri Morozov 0

          Hi Jon!

          I’m not Daniel, but I have some ideas why you need re-write your code or why you need to stay at older framework.

          First of all, you should update your code to .Net Core if you want to save your money. If you are going to full .Net Core (so you need to use EF Core as well), you can use Linux hosting which is cheaper even at Azure. Over there, performance of application is not even comparable, .Net Core is one of the fastest fullstack web frameworks.

          If we go more specific into EF Core, I think that new architecture and design is much better. 90% of all performance issues I met for couple last years was lazy loading and client evaluation. So I was glad to see that client evaluation is now fixed (and I just wondering why lazy loading was introduced back)

          If you don’t need extra performance, Linux hosting and you are OK with your current stack, why you need to rewrite your code at all? Use old stack for existing projects, use new stack for new projects.

          P.S.
          You still can do great things with EF Core, even if it is not so powerful as old one. For example:
          1) Automatic audit https://www.meziantou.net/entity-framework-core-history-audit-table.htm

          2) Multitenant and soft delete https://trailheadtechnology.com/entity-framework-core-2-1-automate-all-that-boring-boiler-plate/

          3) You can even use kind of TPE. The main idea is if base class is not used in navigation properties, database will generate derived objects separately. So your app architecture still can be clean because you can use abstract classes for providing base functionality to your application models.

  • Ian Walker 0

    Why does this page not render correctly in EDGE Version 79.0.279.0 (Official build) dev (64-bit) ??

    https://postimg.cc/wy33k0qh

  • Paolo Fornari 0

    About ‘Interception of database operations‘ there is a way to intercept when a property is populated ?
    In EF 6.2 I now use ObjectMaterializedevent but this is triggered only when a full entity in materialized.

    I need to build a GDPR enabled logging for some entity properties.

Feedback usabilla icon