A general reference for developers looking to migrate from Entity Framework to EF Core
- Syntactical Differences
- Behavioral Differences
- Missing Features
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());
|
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")));
} |
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, 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);
|
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
);
|
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] |
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 |