Entity Framework Core 2 – Breaking changes and obsolescence

 

Entity Framework Core 2 was released on August 14th. It brought new features.

On this article I will explain : Breaking changes and obsolete features

The IDbContextFacfory<T> interface was replaced by IDesignTimeDbContextFactory<T>.

This interface is required when you want to add new migration and update database.

Example:

public class AdventureWorksContextScaffoldedFactory : IDesignTimeDbContextFactory<AdventureWorksContext>
{
   public AdventureWorksContext CreateDbContext(string[] args)
   {
      var builder = new DbContextOptionsBuilder<AdventureWorksContext>();
      builder.UseSqlServer(@const.connectionStringGenerated);
      return new AdventureWorksContext(builder.Options);
   }
}

The extension method UseMemoryDatabase has changed

Now it’s strongly recommanded to use the signature with an in memory database name, because you may have issues if you use multiple databases in memory.

Example:

var serviceProvider = new ServiceCollection()
 .AddDbContextPool<AdventureWorksContext>(
    options =>
    {
       options.UseInMemoryDatabase("AdventureWorks");
    })
 .AddScoped<IEfQueries, EfQueries>()
 .BuildServiceProvider();

If you don’t use the signature with a name, you will get an “obsolete” warning:

Other changes

Package Microsoft.EntityFrameworkCore.SqlServer.Design is deprecated in favor of Microsoft.EntityFrameworkCore.Design(now provider-agnostic).

Only 2.0 providers will work, so any existing providers that target EF Core 1.x will need to be rewritten.

Logging event IDs have changed from the previous version and they are now identical to those used by corresponding ILogger messages. The logger categories now come from subclasses of DbLoggerCategory, such as DbLoggerCategory.Database.CommandDbLoggerCategory.MigrationsDbLoggerCategory.Infrastructure, etc, all of which offer a Name property.

Entity Framework Core 2 – Explicit compiled queries

 

Entity Framework Core 2 was released on August 14th. It brought new features.

On this article I will explain one of them: Explicitly compiled queries

Entity Framework Core included query caching since version 1, but there is still some overhead associated with calculating the key from the query and getting it from the cache. Therefore, version 2 introduced a capability that existed in LINQ to SQL and Entity Framework 5: explicit query compilation and execution. By this, we are able to pre-compile a query and use it in whatever context we want (of a compatible type, of course). We can even eagerly fetch associated collections or entities.

Example:

private static Func<AdventureWorksContextDI, int, Orders> _getOrderById =
  EF.CompileQuery((AdventureWorksContextDI context, int id) =>
  context.WorkOrders.Select(
  x => new Orders
  {
     Id = x.WorkOrderId,
     ProductName = x.Product.Name,
     Quantity = x.OrderQty,
     Date = x.DueDate
  }).FirstOrDefault(x => x.Id == id));

Usage:

public Orders GetOrderByIdCompiled(int id)
{
   return _getOrderById(_context, id);
}

What performance improvments to expect ?

I executed the non compiled query and the same version but compiled (using Stopwatch object), and I measured this:

  • Compiled query: 2 to 15 ms
  • Non compiled query: 4 to 23 ms

 

It looks faster 🙂

Entity Framework Core 2 – DbContext Pools

 

Entity Framework Core 2 was released on August 14th. It brought new features.

On this article I will explain one of them: DbContext Pools

Normally when a DbContext is injected somewhere by the dependency injection framework, a new instance is created every time. With this, we can have a pool of instances, 128 by default. It is a performance improvement and it is configured like this (console app example):

var serviceProvider = new ServiceCollection()
 .AddDbContextPool<AdventureWorksContext>(options => { //options })
 .AddScoped<IEfQueries, EfQueries>()
 .BuildServiceProvider();

.AddDbContext from Entity Framework Core 1 is still implemeted in Entity Framework Core 2.

What kind of improvment to expect ?

Let’s build a Query and let’s see the improvment by using 2 instances of the queries service intantiated by injection dependency system:

public Orders GetOrderById(int id)
{
   return _context.WorkOrders.Select(
                             x => new Orders
                             {
                                Id = x.WorkOrderId,
                                ProductName = x.Product.Name,
                                Quantity = x.OrderQty,
                                Date = x.DueDate
                             }).FirstOrDefault(x => x.Id == id);
}

 

// Using AddDbContext 
var efqueriesService1 = serviceProvider.GetService<IEfQueries>();
efqueriesService1.GetOrders();
var efqueriesService2 = serviceProvider.GetService<IEfQueries>();
efqueriesService2.GetOrders();

// Using AddDbContextPool
var efqueriesService1 = serviceProvider.GetService<IEfQueries>();
efqueriesService1.GetOrders();
var efqueriesService2 = serviceProvider.GetService<IEfQueries>();
efqueriesService2.GetOrders();

I executed this serie of execution 20 times and I measured the execution (using Stopwatch object) this:

With AddDbContext:

  • Instance 1: 23 to 29 ms (instantiation + execution)
  • Instance 2: 7 to 9 ms (instantiation + execution)

With AddDbContextPool:

  • Instance 1: 17 to 21 ms (instantiation + execution)
  • Instance 2: 5 to 7 ms (instantiation + execution)

It looks a bit more performant! 😉