Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EF6 to EF Core porting guide #3509

Merged
merged 25 commits into from
Dec 17, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
02f4a73
EF6 to EF Core porting guide
JeremyLikness Oct 25, 2021
84792c5
Update port-behavior.md
JeremyLikness Oct 25, 2021
9cb7243
Fix name/aliases
JeremyLikness Oct 25, 2021
1c002ec
fix alerts and bullet indentations
JeremyLikness Oct 25, 2021
8069fef
Merge branch 'main' of https://github.com/dotnet/EntityFramework.Docs…
JeremyLikness Oct 26, 2021
e64d2a6
Merge branch 'dotnet:main' into ef6-to-efcore6-port
JeremyLikness Dec 2, 2021
9c975d0
Interim updates
JeremyLikness Dec 3, 2021
384a79e
Merge branch 'main' of https://github.com/dotnet/EntityFramework.Docs…
JeremyLikness Dec 6, 2021
d5b37f9
Continue expanding docs.
JeremyLikness Dec 7, 2021
5220404
Close to first draft!
JeremyLikness Dec 8, 2021
8a916b4
fix end of line
JeremyLikness Dec 8, 2021
5c55538
Final cleanup for first draft
JeremyLikness Dec 8, 2021
da8b2cd
fix description
JeremyLikness Dec 8, 2021
ddbd061
Update entity-framework/efcore-and-ef6/porting/port-database.md
JeremyLikness Dec 9, 2021
a217002
Fix dates
JeremyLikness Dec 9, 2021
5ecb7aa
Merge branch 'ef6-to-efcore6-port' of https://github.com/JeremyLiknes…
JeremyLikness Dec 9, 2021
3413337
Address items from review
JeremyLikness Dec 9, 2021
26487d0
fix lint error
JeremyLikness Dec 9, 2021
56aa80e
Update index.md
JeremyLikness Dec 10, 2021
323a0ac
Update index.md
JeremyLikness Dec 10, 2021
1f95629
Update index.md
JeremyLikness Dec 10, 2021
eafe7d9
Update port-database.md
JeremyLikness Dec 13, 2021
a37f3a8
Merge branch 'dotnet:main' into ef6-to-efcore6-port
JeremyLikness Dec 14, 2021
2be49ad
address arthur's comments
JeremyLikness Dec 14, 2021
772956c
final tweak
JeremyLikness Dec 17, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 48 additions & 38 deletions entity-framework/efcore-and-ef6/porting/index.md
Original file line number Diff line number Diff line change
@@ -1,61 +1,71 @@
---
title: Porting from EF6 to EF Core - EF
description: General information on porting an application from Entity Framework 6 to Entity Framework Core
author: ajcvickers
ms.date: 10/27/2016
title: Port from EF6 to EF Core - EF
description: A detailed guide to port your
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved
author: jeremylikness
ms.alias: jeliknes
ms.date: 10/25/2021
uid: efcore-and-ef6/porting/index
---
# Porting from EF6 to EF Core
# Port from EF6 to EF Core

Because of the fundamental changes in EF Core we do not recommend attempting to move an EF6 application to EF Core unless you have a compelling reason to make the change.
You should view the move from EF6 to EF Core as a port rather than an upgrade.
Entity Framework Core, or EF Core for short, is a total rewrite of Entity Framework for modern application architectures. Due to fundamental changes, there is not a direct upgrade path. The purpose of this documentation is to provide an end-to-end guide for porting your EF6 applications to EF Core.

> [!IMPORTANT]
> Before you start the porting process it is important to validate that EF Core meets the data access requirements for your application.

## Missing features
## When to port

Make sure that EF Core has all the features you need to use in your application. See [Feature Comparison](xref:efcore-and-ef6/index) for a detailed comparison of how the feature set in EF Core compares to EF6. If any required features are missing, ensure that you can compensate for the lack of these features before porting to EF Core.
It is not a requirement that you port your code to EF Core. There are many reasons why you may choose to remain on EF6. The latest version of EF6 supports .NET Core. If your application is running fine and you don't need any of the latest features, you may wish to consider remaining on EF6. Some reasons you might consider porting:
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved

## Behavior changes
- Take advantage of the ongoing performance improvements in EF Core. For example, one customer who migrated from EF6 to EF Core 6 saw a 40x reduction in use of a heavy query due to the [query splitting feature](/ef/core/querying/single-split-queries/). Many customers report enormous performance gains simply by moving to the latest EF Core.

This is a non-exhaustive list of some changes in behavior between EF6 and EF Core. It is important to keep these in mind as your port your application as they may change the way your application behaves, but will not show up as compilation errors after swapping to EF Core.
- Use new features in EF Core. There will be no new features added to EF6. All of the new functionality, for example the [Azure Cosmos DB provider](/ef/core/providers/cosmos/) and [`DbContextFactory`](/ef/core/what-is-new/ef-core-5.0/whatsnew#dbcontextfactory), will only be added EF Core.
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved

### DbSet.Add/Attach and graph behavior
- Modernize your application stack by seamlessly integrating your data access with technologies like gRPC and GraphQL.

JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved
In EF6, calling `DbSet.Add()` on an entity results in a recursive search for all entities referenced in its navigation properties. Any entities that are found, and are not already tracked by the context, are also marked as added. `DbSet.Attach()` behaves the same, except all entities are marked as unchanged.
Regardless of your reasons for considering an upgrade, make sure that EF Core has all the features you need to use in your application. See [Feature Comparison](xref:efcore-and-ef6/index) for a detailed comparison of how the feature set in EF Core compares to EF6. If any required features are missing, ensure that you can compensate for the lack of these features before porting to EF Core.

**EF Core performs a similar recursive search, but with some slightly different rules.**
## Migrations

* The root entity is always in the requested state (added for `DbSet.Add` and unchanged for `DbSet.Attach`).
* **For entities that are found during the recursive search of navigation properties:**
* **If the primary key of the entity is store generated**
* If the primary key is not set to a value, the state is set to added. The primary key value is considered "not set" if it is assigned the CLR default value for the property type (for example, `0` for `int`, `null` for `string`, etc.).
* If the primary key is set to a value, the state is set to unchanged.
* If the primary key is not database generated, the entity is put in the same state as the root.
This documentation uses the terms _port_ and _upgrade_ to avoid confusion with the term [_migrations_](/ef/core/managing-schemas/migrations/) as a feature of EF Core. Migrations in EF Core are fundamentally different than [EF6 Code First migrations](/ef/ef6/modeling/code-first/migrations/). There is not a recommend approach to port your migrations history, so plan to start "fresh" in EF Core. You can maintain the codebase and data from your EF6 migrations. Apply your final migration in EF6, then create an initial migration in EF Core. You will be able to track history in EF Core moving forward.
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved

### Code First database initialization
## Upgrade steps

**EF6 has a significant amount of magic it performs around selecting the database connection and initializing the database. Some of these rules include:**
The upgrade path has been split into several documents that are organized by the phase of your upgrade and the type of application.

* If no configuration is performed, EF6 will select a database on SQL Express or LocalDb.
### Determine your EF Core "flavor"

* If a connection string with the same name as the context is in the applications `App/Web.config` file, this connection will be used.
There are several approaches to how EF Core works with your domain model and database implementation. In general, most apps will follow one of these patterns and how you approach your port will depend on the application "flavor.

* If the database does not exist, it is created.
**Code as the source of truth** is an approach in which everything is modeled through code and classes, whether through data attributes, fluent configuration, or a combination of both. The database is initially generated based on the model defined in EF Core and further updates are typically handled through migrations.

* If none of the tables from the model exist in the database, the schema for the current model is added to the database. If migrations are enabled, then they are used to create the database.
The **Database as source of truth** approach involves reverse-engineering or scaffolding your code from the database. When schema changes are made, the code is either regenerated or updated to reflect the changes.

* If the database exists and EF6 had previously created the schema, then the schema is checked for compatibility with the current model. An exception is thrown if the model has changed since the schema was created.
Finally, a more common **Hybrid mapping** approach follows the philosophy that the code and database are managed separately, and EF Core is used to map between the two. This approach may or may not use migrations.
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved

**EF Core does not perform any of this magic.**

* The database connection must be explicitly configured in code.

* No initialization is performed. You must use `DbContext.Database.Migrate()` to apply migrations (or `DbContext.Database.EnsureCreated()` and `EnsureDeleted()` to create/delete the database without using migrations).

### Code First table naming convention

EF6 runs the entity class name through a pluralization service to calculate the default table name that the entity is mapped to.

EF Core uses the name of the `DbSet` property that the entity is exposed in on the derived context. If the entity does not have a `DbSet` property, then the class name is used.
> [!IMPORTANT]
> EF6 supported a special model definition format named **Entity Data Model XML (EDMX)**. EDMX files contain multiple definitions, including conceptual schema definitions (CSDL), mapping specifications (MSL), and store schema definitions (SSDL). EF Core tracks the domain, mapping, and database schemas through internal model graphs and does not support the EDMX format. Many blog posts and articles mistakenly claim this means EF Core only supports code first. EF Core supports all three application models described in the previous section. You can rebuild the model in EF Core by [reverse-engineering the database](/ef/core/managing-schemas/scaffolding). If you use EDMX for a visual representation of your entity model, consider using the open source [EF Core Power Tools](https://github.com/ErikEJ/EFCorePowerTools).

### Perform the upgrade steps

The following documents detail specific steps for the port. At a high level, you will:

1. [Review behavior changes between EF6 and EF Core](/efcore-and-ef6/porting/port-behavior).
1. Perform your final migrations, if any, in EF6.
1. Create your EF Core project.
1. Either copy code to the new project, run reverse-engineering, or a combination of both.
1. Rename references and entities and update behaviors:
- `System.Data.Entity` to `Microsoft.EntityFrameworkCore`
- Change `DbContext` constructor to consume options and/or override `OnConfiguring`
- `DbModelBuilder` to `ModelBuilder`
- Rename `DbEntityEntry<T>` to `EntityEntry<T>`
- Move from `Database.Log` to `Microsoft.Extensions.Logging APIs`
- `WithRequired` to `WithOne` and `IsRequired(true)`
- `WithOptional` to `WithOne` and `IsRequired(false)`
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved
- Update validation code. There is no data validation built into EF Core, but you can [do it yourself](/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/domain-model-layer-validations#use-validation-attributes-in-the-model-based-on-data-annotations).
1. Perform specific steps based on your EF Core approach:
- [Code as source of truth](/efcore-and-ef6/porting/port-code.md)
- [Database as source of truth](/efcore-and-ef6/porting/port-database.md)
- [Hybrid model](/efcore-and-ef6/porting/port-hybrid.md)

Finally, review some ways to address and work around the [edge cases](/efcore-and-ef6/porting/port-code.md).
49 changes: 49 additions & 0 deletions entity-framework/efcore-and-ef6/porting/port-behavior.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: Porting from EF6 to EF Core - Behavior changes
description: A non-exhaustive list of some changes in behavior between EF6 and EF Core.
author: ajcvickers
ms.date: 10/27/2016
uid: efcore-and-ef6/porting/port-behavior
---
# Behavior Changes between EF6 and EF Core

This is a non-exhaustive list of some changes in behavior between EF6 and EF Core. It is important to keep these in mind as your port your application as they may change the way your application behaves, but will not show up as compilation errors after swapping to EF Core.

## DbSet.Add/Attach and graph behavior

In EF6, calling `DbSet.Add()` on an entity results in a recursive search for all entities referenced in its navigation properties. Any entities that are found, and are not already tracked by the context, are also marked as added. `DbSet.Attach()` behaves the same, except all entities are marked as unchanged.

JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved
**EF Core performs a similar recursive search, but with some slightly different rules.**

* The root entity is always in the requested state (added for `DbSet.Add` and unchanged for `DbSet.Attach`).
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved
* **For entities that are found during the recursive search of navigation properties:**
* **If the primary key of the entity is store generated**
* If the primary key is not set to a value, the state is set to added. The primary key value is considered "not set" if it is assigned the CLR default value for the property type (for example, `0` for `int`, `null` for `string`, etc.).
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved
* If the primary key is set to a value, the state is set to unchanged.
* If the primary key is not database generated, the entity is put in the same state as the root.

## Code First database initialization

**EF6 has a significant amount of magic it performs around selecting the database connection and initializing the database. Some of these rules include:**
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved

* If no configuration is performed, EF6 will select a database on SQL Express or LocalDb.

* If a connection string with the same name as the context is in the applications `App/Web.config` file, this connection will be used.

* If the database does not exist, it is created.

* If none of the tables from the model exist in the database, the schema for the current model is added to the database. If migrations are enabled, then they are used to create the database.

* If the database exists and EF6 had previously created the schema, then the schema is checked for compatibility with the current model. An exception is thrown if the model has changed since the schema was created.

**EF Core does not perform any of this magic.**

* The database connection must be explicitly configured in code.

* No initialization is performed. You must use `DbContext.Database.Migrate()` to apply migrations (or `DbContext.Database.EnsureCreated()` and `EnsureDeleted()` to create/delete the database without using migrations).

## Code First table naming convention

EF6 runs the entity class name through a pluralization service to calculate the default table name that the entity is mapped to.

EF Core uses the name of the `DbSet` property that the entity is exposed in on the derived context. If the entity does not have a `DbSet` property, then the class name is used.
10 changes: 10 additions & 0 deletions entity-framework/efcore-and-ef6/porting/port-database.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: Port from EF6 to EF Core - Database as Source of Truth
description: How to port from EF6 to EF Core when you generate your model from the database.
author: jeremylikness
ms.alias: jeliknes
ms.date: 10/25/2021
uid: efcore-and-ef6/porting/port-database
---

This is a work in progress.
10 changes: 10 additions & 0 deletions entity-framework/efcore-and-ef6/porting/port-edge-cases.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: Port from EF6 to EF Core - Edge Cases
description: Guide to solutions, fixes, and workarounds for common issues that come up during the port from EF 6 to EF Core.
author: jeremylikness
ms.alias: jeliknes
ms.date: 10/25/2021
uid: efcore-and-ef6/porting/port-edge-cases
---

This is a work in progress.
10 changes: 10 additions & 0 deletions entity-framework/efcore-and-ef6/porting/port-hybrid.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
title: Port from EF6 to EF Core - Hybrid Approach
description: How to port from EF6 to EF Core when you iterate your domain model and database separately and use mapping to connect the two.
author: jeremylikness
ms.alias: jeliknes
ms.date: 10/25/2021
uid: efcore-and-ef6/porting/port-hybrid
---

This is a work in progress.