Volodymyr Bilyachat

Melbourne, Australia

How to upgrade Entityframework to the Core

02 September 2018

Introduction

Note: At moment of writing I am using EFCore 2.1.1

I like learning when I am doing practical tasks, then I can dive into the problem and fully understand differences between version of frameworks. Also as a developer I have pet project :) I started it more than 5 years and still doing it why? Well because I am learning and I don’t believe that I can be good without those projects. Because at work I try to be practical while at my project I can do as I wish and learn how to do and how to not.

So for long time I did wanted to upgrade my project to latest tech and finally few weeks ago I’ve done it and I want to share what I’ve learned

Entity Framework Core

First I think that Microsoft messed up with names. Core does not mean that it must be compiled with .net core. But good news that you can include it in you projects where you can use .net core because of some legacy. Entityframework Core is compiled with .NETStandard means that you can reference it in .Net Framework 4.6.2 and up. So this is my case because I still have few librarries which are not yet .NetStandard ready.

I started my Upgrade with article from Microsoft which says well remove old libraries and add new. I did but it wasn’t so easy in the end.

EF and EF Core what are the differences

Constructor

base("name=mydbentities")-> YourContextContext(DbContextOptions options) : base(options)

In old (let me call like that) EF we used to have constructor with string now it accepts DbContextOptions

OnModelCreating

OnModelCreating(DbModelBuilder modelBuilder) -> OnModelCreating(ModelBuilder modelBuilder) 

Change is very minor so class name changed names

SqlQuery

If you are using SqlQuery in EF then its bit of a trouble, because there is no direct replacement for this method. There are some manual steps to be done. Firstly need to register View in OnModelCreating  More info can be found at github issue

Many to many

In EF I used to create many to many by adding collection property on both classes. For instance

public class Category{
......
public ICollection<DancerClass> Classes{get;set;}
......
}

public class DancerClass{
......
public ICollection<Category> Categories{get;set;}
......
}

This is not supported in EFCore you will need to modify to be

  public class CategoryToDancerClass
    {
        public DancerClass DancerClass { get; set; }
        public Category Category { get; set; }
        public int DancerClass_Id { get; set; }
        public int Category_Id { get; set; }
    }

public class Category{
......
      public ICollection<CategoryToDancerClass> Classes{get;set;}
......
}

public class DancerClass{
......
public ICollection<CategoryToDancerClass> Categories{get;set;}
......
}

Also you will need to provide information OnModel

    modelBuilder.Entity<CategoryToDancerClass>()
                .ToTable("DancerClassCategories")
                .HasKey(sc => new { sc.DancerClass_Id, sc.Category_Id});
            modelBuilder.Entity<CategoryToDancerClass>()
                .HasOne(sc => sc.DancerClass)
              .WithMany(s => s.Categories)
                .HasForeignKey(sc => sc.DancerClass_Id);
            modelBuilder.Entity<CategoryToDancerClass>()
                .HasOne(sc => sc.Category)
                .WithMany(s => s.DancerClasses)
                .HasForeignKey(sc => sc.Category_Id);

So if you are planning upgrade this would be good point to go via all of you classes and modify in old code base to have less issues later.

Include: Select into ThenInclude

      public virtual Dancer GetForEdit(int id)
        {
            return _db.Dancers
                .Include(d => d.Classes)
                .Include(d => d.Classes.Select(c => c.DancerClass))
                .Include(d => d.Classes.Select(c => c.ProgramType))
                .Include(d => d.Organisations)
                .AsNoTracking()
                .FirstOrDefault(i => i.Id == id);
        }

Will become in core

        public virtual Dancer GetForEdit(int id)
        {
            return _db.Dancers
                .Include(d => d.Classes)
                .Include(d => d.Classes).ThenInclude(c => c.DancerClass)
                .Include(d => d.Classes).ThenInclude(c => c.ProgramType)
                .Include(d => d.Organisations)
                .AsNoTracking()
                .FirstOrDefault(i => i.Id == id);
        }

Lazy-loading

Only in EFCore 2.1 lazy loading was implemented. To implement lazy loading there is two ways.

  1. Install package Microsoft.EntityFrameworkCore.Proxies, but there is feature request because now to use lazy loading all navigation properties must be virtual. There is github issue with feature request.
  2. Lazy loading without proxies