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 1 commit
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
26 changes: 14 additions & 12 deletions entity-framework/efcore-and-ef6/porting/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,57 +11,59 @@ uid: efcore-and-ef6/porting/index
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.
> Before you start the porting process it is important to validate that EF Core meets the data access requirements for your application. You can find everything you need in the [EF Core documentation](/ef/core/).

## When to port

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:
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, .NET 5 and .NET 6. 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:

- 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.

- 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

- Modernize your application stack by seamlessly integrating your data access with technologies like gRPC and GraphQL.
- Modernize your application stack by using dependency injection and seamlessly integrating your data access with technologies like gRPC and GraphQL.

For a full comparison of EF6 to EF Core, including several features exclusive to EF Core, see: [Compare EF Core & EF6](/ef/efcore-and-ef6/).

JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved
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.

## Migrations

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.
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 not compatible with [EF6 Code First migrations](/ef/ef6/modeling/code-first/migrations/) due to significant improvements to how migrations are handled. There is not a recommended 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.

## Upgrade steps

The upgrade path has been split into several documents that are organized by the phase of your upgrade and the type of application.

### Determine your EF Core "flavor"

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.
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".

**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.
**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. This is often referred to as "code first," but the name isn't entirely accurate because one approach is to start with an existing database, generate your entities, and then maintain with code moving forward.

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.
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. This is often called "database first."

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.
Finally, a more advanced **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 typically eschews migrations.

The following table summarizes some high level differences:

|**Approach**|**Developer role**|**DBA role**|**Migrations**|**Scaffolding**|**Repo**|
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved
|---|---|---|---|---|---|
|**Code first**|Design entities and generated migrations|Verify schema definitions and changes|Per commit|N/A|Track entities, DbContext, and migrations|
|**Code first**|Design entities and verify/customize generated migrations|Verify schema definitions and changes|Per commit|N/A|Track entities, DbContext, and migrations|
|**Database first**|Reverse engineer after changes and verify generated entities|Inform developers when the database changes to re-scaffold|N/A|Per schema change|Track extensions/partial classes that extend the generated entities|
|**Hybrid**|Update fluent configuration to map whenever entities or database change|Inform developers when the database has changed so they can update entities and model configuration|N/A|N/A|Track entities and DbContext|

The hybrid approach imposes the most overhead and is the least common.
The hybrid approach is a more advanced approach with additional overhead compared to the traditional code and database approaches.

### Understand the impact of moving away from EDMX

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).
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 state 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) that provide similar capabilities for EF Core.

For more information on the impact of lack of support for EDMX files, read the [porting EDMX](/efcore-and-ef6/porting/port-edmx#other-considerations) guide.

### Perform the upgrade steps

The following documents detail specific steps for the port. Note that it is not a requirement to port the entire application. EF6 and EF Core can run in the same application (see: [using EF Core and EF6 in the same application](/ef/efcore-and-ef6/side-by-side?branch=pr-en-us-3509)). To minimize risk, you might consider:
It is not a requirement to port the entire application. EF6 and EF Core can run in the same application (see: [using EF Core and EF6 in the same application](/ef/efcore-and-ef6/side-by-side?branch=pr-en-us-3509)). To minimize risk, you might consider:

1. Move to EF6 on .NET Core if you haven't already.
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved
1. Migrate a small portion of your app to EF Core and run it side-by-side with EF6.
Expand Down
4 changes: 3 additions & 1 deletion entity-framework/efcore-and-ef6/porting/port-behavior.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ In EF6, calling `DbSet.Add()` on an entity results in a recursive search for all

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`).
* If the root entity is configured for a generated key and the key is not set, it will be put into the `Added` state.
* **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.

For more information on these behaviors in EF Core, read [Change Tracking in EF Core](/ef/core/change-tracking/).

## 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
Expand Down
4 changes: 3 additions & 1 deletion entity-framework/efcore-and-ef6/porting/port-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Most APIs that you use in EF6 are in the `System.Data.Entity` namespace (and rel

## Context configuration (connection etc.)

As described in [Ensure EF Core Will Work for Your Application](xref:efcore-and-ef6/porting/index), EF Core has less magic around detecting the database to connect to. You will need to override the `OnConfiguring` method on your derived context, and use the database provider specific API to setup the connection to the database.
As described in [configuring the database connection](/ef/efcore-and-ef6/porting/port-detailed-cases?#configuring-the-database-connection), EF Core has less magic around detecting the database to connect to. You will need to override the `OnConfiguring` method on your derived context, and use the database provider specific API to setup the connection to the database.
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved

Most EF6 applications store the connection string in the applications `App/Web.config` file. In EF Core, you read this connection string using the `ConfigurationManager` API. You may need to add a reference to the `System.Configuration` framework assembly to be able to use this API.

Expand Down Expand Up @@ -53,3 +53,5 @@ If possible, it is best to assume that all previous migrations from EF6 have bee
## Test the port

Just because your application compiles, does not mean it is successfully ported to EF Core. You will need to test all areas of your application to ensure that none of the behavior changes have adversely impacted your application.

Finally, review the [detailed cases to consider when porting](/ef/efcore-and-ef6/porting/port-detailed-cases) for more advice on specific cases and scenarios in your code.
4 changes: 3 additions & 1 deletion entity-framework/efcore-and-ef6/porting/port-database.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ uid: efcore-and-ef6/porting/port-database
If you're using the database as the source of truth, your migration will mostly involve addressing any changes to the shape of entities generated. The steps to migrate include:
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved

1. Pick a point-in-time to model the database.
1. Ensure your EF6 projects and up to date and in-sync with the database.
1. Ensure your EF6 projects are up to date and in-sync with the database.
1. Create the EF Core project.
1. Use the [scaffolding tools](/ef/core/managing-schemas/scaffolding) to reverse-engineer your database to code.
JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved
1. Validate that the EF Core generated classes are compatible with your code.
Expand All @@ -35,3 +35,5 @@ You may want to consider an alternate workflow and follow steps similar to the [
## Customize the code generation

As of EF Core 6, it is possible to customize the code generated by scaffolding by using [T4 templates](/visualstudio/modeling/code-generation-and-t4-text-templates). See [T4 and EF Core Reverse Engineering](https://www.bricelam.net/2020/02/03/t4-and-efcore.html) for details.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"As of EF Core 6, it is possible to customize..." It is currently not possible.


JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved
Finally, review the [detailed list of differences between EF6 and EF Core](/ef/efcore-and-ef6/porting/port-detailed-cases) to address any remaining issues with porting.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ EF6 supported table-per-hierarchy (TPH), table-per-type (TPT) and table-per-conc

### Attributes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"For spatial support, EF Core recommends using a third-party library such as NetTopologySuite." I would change this to indicate that EF Core integrates with NTS. Using a different third-party library won't work unless this same integration work is done, which is non-trivial. Something like, "For spatial support, EF Core integrates with the third-party community library NetTopologySuite."

JeremyLikness marked this conversation as resolved.
Show resolved Hide resolved

EF6 supported index attributes on properties. In EF Core, they are applied at the type level which should make it easier for scenarios that require composite indexes. EF core
EF6 supported index attributes on properties. In EF Core, they are applied at the type level which should make it easier for scenarios that require composite indexes. EF Core doesn't support composite keys with data annotations (i.e. using Order in `ColumnAttribute` together with `KeyAttribute`).

### Required and optional

Expand Down
2 changes: 2 additions & 0 deletions entity-framework/efcore-and-ef6/porting/port-edmx.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,5 @@ Just because your application compiles, does not mean it is successfully ported
EF Core does not support the `EntityClient` provider and therefore any [EntitySQL](/dotnet/framework/data/adonet/ef/language-reference/entity-sql-language) queries must be migrated to LINQ or `FromRawSql`.

Furthermore, there is no support for [EntityClient connection strings](/ef/ef6/fundamentals/configuring/connection-strings#databasemodel-first-with-connection-string-in-appconfigwebconfig-file).

For more considerations, read the complete guide to [differences between EF6 and EF Core](/efcore-and-ef6/porting/port-detailed-cases.md).
2 changes: 1 addition & 1 deletion entity-framework/efcore-and-ef6/porting/port-hybrid.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ uid: efcore-and-ef6/porting/port-hybrid

# Port from EF6 to EF Core - the Hybrid Approach

Code first generates the database from your code. Database first generates your code from the database. In the hybrid approach, you don't generate anything. Instead, you let the database and codebase evolve and use model configuration to keep the two in sync. This page contains some tips for success using the hybrid approach:
Two common approaches are to generate your database from code and use migrations, or generate your entities from the database using reverse-engineering. In the hybrid approach, you don't generate anything. Instead, you let the database and codebase evolve and use model configuration to keep the two in sync. This page contains some tips for success using the hybrid approach:

1. First, read the guides for [code as source of truth](/efcore-and-ef6/porting/port-code) and [database as source of truth](/efcore-and-ef6/porting/port-database) to familiarize yourself with some of the considerations to be aware of.
1. Because you won't be using migrations, there is no need to model sequences, non-primary indexes, constraints and index filters.
Expand Down