Skip to content

Latest commit

 

History

History
881 lines (830 loc) · 20 KB

README.md

File metadata and controls

881 lines (830 loc) · 20 KB

Entity Framework to EF Core Porting Reference

A general reference for developers looking to migrate from Entity Framework to EF Core


Table of Contents



Syntactical Differences

Namespace Changes

Description EF Example EF Core Example
Entity Framework namespace
Replaced by EF Core namespace
using System.Data.Entity;
      
using Microsoft.EntityFrameworkCore;
      
Spatial data types
Requires Nuget package: NetTopologySuite
using Microsoft.SqlServer.Types;
      
using NetTopologySuite.Geometries;

optionsBuilder.UseSqlServer(connectionString, options => options.UseNetTopologySuite());
      

Configuration Changes

Description EF Example EF Core Example
Config files
web.config and app.config replaced by appsettings.json
<configuration>
  <connectionStrings>
    <add name="myConnection"
        connectionString="server=localhost;database=mydatabase;" />
  </connectionStrings>
</configuration>
      
appsettings.json
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=MyDatabase;Trusted_Connection=True;"
  },
}
      
startup.cs
using Microsoft.Extensions.Configuration;
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<MyDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}

DbContext Changes

Required changes for the DbContext class

Description EF Example EF Core Example
Connection strings
No longer passed into the base constructor. Set the connection string with the DbContextOptionsBuilder class.
public MyBloggingContext(string nameOrConnectionString) 
    : base(nameOrConnectionString) 
{
}
      
private readonly string _connectionString;
public MyBloggingContext(string connectionString)
{
    _connectionString = connectionString;
}

public override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer(_connectionString);
}

See "Configuration Changes" section above for an ASP.NET Core example with connection string configuration in a startup.cs file.
Registering database providers
Provider registration must be done in code using the DbContextOptionsBuilder class or in startup.cs
(set in web.config/app.config or with DbConfiguration.SetProviderServices() method) MyDbContext.cs
// .UseSqlServer() registers Sql Server as the provider.
//  Change according the database being used
// Ex: .UseNpgsql() registers Postgres (also requires the 
//  Npgsql.EntityFrameworkCore.PostgreSQL Nuget package)
public override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder.UseSqlServer(_connectionString);
}
      

See "Configuration Changes" section above for an ASP.NET Core example with database provider registration in a startup.cs file.
Eager Loading
Eagerly loading related entities using a .Select() drill-down has been replaced by .ThenInclude().
context.Blogs.Where(b => b.Title == "MyBlogTitle")
    .Include(b => b.Author)
    .Include(b => b.Posts.Select(p => p.Content))
    .Include(b => b.Posts.Select(p => p.Comments));
      
context.Blogs.Where(b => b.Name == "PortEF6ToCore")
    .Include(b => b.CreatedBy)
    .Include(b => b.Posts).ThenInclude(p => p.Content))
    .Include(b => b.Posts).ThenInclude(p => p.Comments));
      
Lazy Loading
Must be enabled using the DbContextOptionsBuilder class or with an ILazyLoader service.
dbContext.Configuration.LazyLoadingEnabled = true; 

dbContext.Configuration.LazyLoadingEnabled = false; 
      
// lazy loading disabled by default
// lazy loading enabled via proxies
optionsBuilder.UseLazyLoadingProxies()
      
// lazy loading enabled via ILazyLoader service
// requires adding the Nuget package Microsoft.EntityFrameworkCore.Abstractions
using Microsoft.EntityFrameworkCore.Infrastructure;

public class Blog
{
    private readonly ILazyLoader _lazyLoader;
    
    public Blog()
    {
    }
    
    public Blog(ILazyLoader lazyLoader)
    {
        _lazyLoader = lazyLoader;
    }
    
    private List _posts;
    public List Posts
    {
        get => _lazyLoader.Load(this, ref _posts);
        set => _posts = value;
    }
}
      
Enabling proxy creation
context.Configuration.ProxyCreationEnabled = true;

context.Configuration.ProxyCreationEnabled = false;
      
// proxies are disabled by default
optionsBuilder.UseLazyLoadingProxies()
      
Logging generated SQL
Logging method is set using the DbContextOptionsBuilder class.
dbContext.Database.Log = Console.WriteLine;
      
using Microsoft.Extensions.Logging namespace;

optionsBuilder.UseLoggerFactory(LoggerFactory.Create(Console.WriteLine));
      
DbSet.Local property
Now returns a LocalView<TEntity> instead of an ObservableCollection<T>
var local = dbContext.Blogs.Local;
      
var local = dbContext.Blogs.Local.ToObservableCollection();
      
Database Creation/Deletion
Methods to create/delete a database have been renamed.
dbContext.Database.CreateIfNotExists();
dbContext.Database.Delete();
      
dbContext.Database.EnsureCreated();
dbContext.Database.EnsureDeleted();
      
Return type of DbSet<T>.Add()
Changed from T to EntityEntry<T>
Blog added = dbContext.Blogs.Add(blog);
      
Blog added = dbContext.Blogs.Add(blog).Entity;
      

DbModelBuilder Changes

DbModelBuilder, often used in the DbContext.OnModelCreating() method, requires the following changes:

Description EF Example EF Core Example
Renamed DbModelBuilder class to ModelBuilder

public void OnModelCreating(DbModelBuilder modelBuilder)
      
public void OnModelCreating(ModelBuilder modelBuilder)
      
Many:Required relationship configuration
.WithRequired() replaced by .WithOne().IsRequired()
modelBuilder.Entity<Blog>()
    .HasMany(b => b.Posts)
    .WithRequired(p => p.Blog)
    .HasForeignKey(p => p.BlogId)
    .WillCascadeOnDelete(true);
      
modelBuilder.Entity<Blog>()
    .HasMany(b => b.Posts)
    .WithOne(p => p.Blog)
    .IsRequired(true)
    .HasForeignKey(p => p.BlogId)
    .OnDelete(DeleteBehavior.Cascade)
      
Delete behavior
.WillCascadeOnDelete() replaced by .OnDelete()
.WillCascadeOnDelete(true);
.WillCascadeOnDelete(false);
      
.OnDelete(DeleteBehavior.Cascade);
.OnDelete(DeleteBehavior.Restrict);
      

Data Access and Tracking Changes

Changes in how data is accessed and tracked

Description EF Example EF Core Example
Renamed DbChangeTracker to ChangeTracker
private void DisplayTrackedEntities(DbChangeTracker changeTracker)
{
}
      
using Microsoft.EntityFrameworkCore.ChangeTracking;

private void DisplayTrackedEntities(ChangeTracker changeTracker)
{
}
      
Replaced DbContextTransaction with IDbContextTransaction
DbContextTransaction transaction = dbContext.Database.BeginTransaction();
      
using Microsoft.EntityFrameworkCore.Storage;

IDbContextTransaction transaction = dbContext.Database.BeginTransaction();
      
Raw SQL Queries (returning entities)
// Sql string
DbSet.SqlQuery("SELECT * FROM MyTable");

// Parameterized query
DbSet.SqlQuery("SELECT * FROM MyTable WHERE id={0}", id);
      
// Sql string
DbSet.FromSqlRaw("SELECT * FROM MyTable");

// Parameterized query
DbSet.FromSqlRaw("SELECT * FROM MyTable WHERE id={0}", id);

// Parameterized query with interpolated string
DbSet.FromSqlInterpolated($"SELECT * FROM MyTable WHERE id={id}");
      
Raw SQL Queries (commands)
// Sql string
dbContext.Database.ExecuteSqlCommand("sp_UpdateAll");

// Parameterized query
dbContext.Database.ExecuteSqlCommand("sp_InsertId {0}", id);
      
// Sql string
dbContext.Database.ExecuteSqlRaw("sp_UpdateAll");

// Parameterized query
dbContext.Database.ExecuteSqlRaw("sp_InsertId {0}", id);

// Parameterized query with interpolated string
dbContext.Database.ExecuteSqlInterpolated($"sp_InsertId {id}");
      
Compiled queries
using System.Data.Objects;

CompiledQuery.Compile<TContext, TParam1, ..., TParamN, TResult>(
    // LINQ query
);
      
using Microsoft.EntityFrameworkCore;

EF.CompileQuery<TContext, TParam1, ..., TParamN, TResult>(
    // LINQ query
);
      

Behavioral Changes

These Entity Framework features exhibit different behavior in Entity Framework Core. Here's what to watch out for:

Feature EF Behavior EF Core Behavior
Lazy loading Enabled by default Not enabled by default
Lazy loading by proxies Use of lazy loading proxies can be set on the fly with the follow statements:
context.Configuration.ProxyCreationEnabled = true;
context.Configuration.ProxyCreationEnabled = false;
      
Dynamically enabling/disabling lazy loading proxies no longer exists in EF Core. Use of lazy loading proxies can only be set upon DbContext instantiation.
Change tracking [placeholder] [placeholder]

Missing Features

These Entity Framework features are missing from EF Core and may or may not be implemented in the future. If your project uses any of these features, consider using EF v6.3+

Name Description Implementation Plan
TPC (Table-per-Concrete) Allows entity classes with an abstract base class to be mapped to separate database tables (abstract base class remains unmapped) On backlog
Entity splitting
Allows single entities to be mapped to multiple tables (i.e. a subset of properties mapped to one table, another subset mapped to another table). On backlog
Visual Designer
GUI-based db modeling tool that automatically generates DbContext and entity classes from a UML diagram. It also includes additional features such as auto-generated CUD stored procedures. Not planned
ObjectContext class
A low level class used to facilitate data access in a generic manner. It is commonly used when a stored procedure returns multiple result sets that each map to a different entity type. Not planned