Featured resource
2025 Tech Upskilling Playbook
Tech Upskilling Playbook

Build future-ready tech teams and hit key business milestones with seven proven plays from industry leaders.

Check it out
  • Lab
    • Libraries: If you want this lab, consider one of these libraries.
    • Core Tech
Labs

Guided: EF Core Migrations and Database Schema Refactoring

Entity Framework Core is a powerful Object-Relational Mapping framework designed to simplify database schema management through its comprehensive suite of tools. In this hands-on lab, you will learn how to initialize your project with EF Core Migrations, enabling you to seamlessly manage and evolve your database schema in alignment with your entity model. This lab is ideal for developers looking to enhance their database management skills, offering practical experience in applying EF Core's capabilities to real-world scenarios.

Lab platform
Lab Info
Level
Intermediate
Last updated
Dec 22, 2025
Duration
40m

Contact sales

By clicking submit, you agree to our Privacy Policy and Terms of Use, and consent to receive marketing emails from Pluralsight.
Table of Contents
  1. Challenge

    Welcome to the lab:

    Welcome to the lab:

    Guided: EF Core Migrations and Database Schema Refactoring

    Entity Framework Core (EF Core) stands out as a robust Object-Relational Mapping (ORM) framework, providing .NET developers with a suite of tools to efficiently work with databases. Among its many features, EF Core's ability to manage database schemas through migrations significantly streamlines the development process.

    Migrations in EF Core serve as a bridge between your entity model's evolution and your database schema. As your application grows and your models change, migrations track these modifications and translate them into SQL commands. These commands are then executed against your database, ensuring that its schema aligns with your current model without losing data or compromising integrity.

    Why Use Migrations? #### Version Control for Database Schema Migrations extend the benefits of version control systems to your database schema, allowing you to:
    • Track and document changes over time.
    • Explore the evolution of your database schema with ease.
    • Roll back to previous states if necessary, enhancing safety and flexibility in your development process.

    Synchronization Between Environments

    Migrations play a crucial role in maintaining consistency across various environments, such as development, testing, and production. This synchronization ensures that:

    • All team members work with the same database schema.
    • The transition of code between environments is smooth, reducing environment-specific bugs and discrepancies.

    Collaboration and Deployment

    By systematizing schema changes, migrations significantly improve collaboration among team members and streamline the deployment process:

    • Team members can easily apply and revert schema changes, facilitating a collaborative development environment.
    • Migrations automate schema updates during application deployment, ensuring compatibility between the application and its database schema. This automation minimizes manual intervention and the risk of deployment errors.

    Components of a Migration

    EF Core Migrations are a set of tools designed to manage database schema changes in a controlled and versioned manner.

    They consist of:

    Migration Schema Files

    EF Core automatically generates two C# files for each migration: a schema file and a design file.

    The schema file contains two essential methods:

    • The Up method applies changes to the database schema, such as creating or altering tables and columns.
    • The Down method reverses the changes made by the Up method, allowing you to revert your database schema to a previous state.

    The design file contains metadata about the migration and a model snapshot. This snapshot represents the state of the model and the database schema at the time of the migration, aiding EF Core in understanding how the model has evolved and how to manage subsequent migrations effectively.

    While EF Core generates these files for you, editing them may be necessary for complex schema changes or to incorporate custom SQL commands. This flexibility allows for precise control over how migrations are applied and reverted, ensuring that your database schema evolves in line with your application's requirements.

    Snapshot Files

    With each migration, EF Core updates a snapshot of your current model's schema. This snapshot reflects the state of the model at the time of the migration's creation and is used by EF Core to determine the changes required for the next migration. It helps EF Core understand the evolution of your model over time and ensures that migrations are consistently applied.

    Migration History Table

    EF Core tracks which migrations have been applied to your database through a special table, typically named __EFMigrationsHistory. This table contains records of all executed migrations, providing EF Core with the information needed to determine which migrations should be applied or reverted during updates. It is a critical component for maintaining the consistency of your database schema across different environments and deployments.

    To advance your understanding and application of EF Core Migrations, please click the right arrow

  2. Challenge

    Getting Started

    Getting Started

    Before diving into the practical exercises, take a moment to familiarize yourself with the lab's interface.

    Lab Environment ---- #### Explorer Tab Access the filesystem quickly through the **Explorer** tab, marked by the stacked paper icon at the top left. Open this tab whenever you need to interact with the project files.

    Source Control

    This lab utilizes source control to assist you in navigating changes to files.

    Should you encounter any difficulties with a specific step, you can access guidance through the Source Control tab, marked with the branch icon.

    Within the main branch, you'll find the final state of each file. This allows you to either open the changed file to view the necessary changes or simply use the back arrow to revert the file to its final state.

    Installed Tooling

    To facilitate the creation and execution of EF Core Migrations, which is a design-time activity, two key components are required:

    EF Core CLI

    The EF Core command-line tools are pivotal for migration tasks. There are two primary ways to integrate these tools, depending on your development environment:

    For Visual Studio Users: The Package Manager Console (PMC) tools can be installed with the command:

    Install-Package Microsoft.EntityFrameworkCore.Tools
    

    For .NET Core CLI Users: The dotnet-ef tool can be installed with the command:

    dotnet tool install --global dotnet-ef
    

    Since this lab environment is running on Linux and is using the .NET Core CLI, the dotnet-ef tool has been installed.

    You can verify that the dotnet-ef tool is available by running the following command in the terminal:

    dotnet ef
    
    EF Core Design Package **Microsoft.EntityFrameworkCore.Design Package**

    In addition to the command-line tooling, the project itself needs to also reference the Microsoft.EntityFrameworkCore.Design package. This package provides the necessary API for design-time services that EF Core uses to create migrations and other tasks that require metadata about the model.

    When using the PMC migrations tool, this package is automatically included for you.

    When using the .NET Core CLI, you will need to add this package into the project containing your DbContext using the command:

    dotnet add package Microsoft.EntityFrameworkCore.Design
    

    You can see that this has been added to the LMS project file.

    Open the LMS.csproj file.

    What are and the <IncludeAssets> and <PrivateAssets> tags in your <PackageReference> for Microsoft.EntityFrameworkCore.Design ensure that the necessary design-time tools and assets are included and used by your project without exposing these assets to any projects that might reference yours.

    This setup is typical for development-time tools like EF Core's design package, which provides scaffolding and other design-time capabilities but isn't required by consuming projects at runtime.

    Note:
    These components have already been installed for use in this lab. This detail is provided for your reference when setting up your own projects in the future.

    Current State of Project This LMS (Library Management System) project is designed to streamline the managment of books within your personal library. Featuring a user-friendly command-line interface for interacting with the library, this system efficiently stores and retrieves information using an SQLite database named `Library.sqlite`.

    During the initial prototyping phase of this project, the .EnsureCreated() method of the DbContext was used to swiftly create the database and its schema.

    This method facilitated a quick setup, enabling immediate development and testing. However, as the entity model evolved, the .EnsureDeleted() method had to be used to remove the existing database, followed by .EnsureCreated() to regenerate it with the updated schema.

    This process, while effective for rapid prototyping, necessitates the complete deletion and recreation of the database with every model change, leading to the loss of persisted data.

    This approach, illustrated in the Program.cs file, is not viable for long-term development due to its data-destructive nature:

    As the project begins to evolve beyond the prototyping phase, it's crucial to adopt a more sustainable strategy for database schema management.

    EF Core Migrations offer a robust solution, allowing for incremental schema updates without sacrificing existing data. Migrations enable the database schema to evolve in tandem with the entity model, ensuring data persistence through changes.

    Preparing for EF Core Migrations

    To shift towards using EF Core Migrations, you will need to remove the current database creation process.

    Start by eliminating the .EnsureDeleted() and .EnsureCreated() lines from the Program.cs file, preventing automatic database recreation upon application start.

    Open the Program.cs file

    Then you must drop the existing database. This step is essential to start a clean migration history that EF Core will manage. In the Terminal, execute:

    dotnet ef database drop
    

    Caution: Ensure you have backed up any necessary data before dropping the database, as this command will irreversibly remove it.

    By preparing your project for EF Core Migrations, you lay the foundation for a more flexible and resilient database schema management strategy, facilitating smoother development cycles and data integrity as your application grows.

    Ready to take the next step? Click the right arrow to begin transitioning to using EF Core Migrations.

  3. Challenge

    Initialize Migrations

    Initialize Migrations

    EF Core Migrations are an essential part of managing database schema changes, and they are primarily managed through command-line tools.

    This lab will be utilizing the .NET Core CLI tools to handle migrations. It's important to note, however, that if you're working within Visual Studio, equivalent PowerShell commands are available to achieve similar outcomes.

    1️⃣ Create the Initial Migration

    To kickstart your journey with EF Core Migrations, the first step is to create your initial migration.

    Open the Terminal window and execute the following command:

    dotnet ef migrations add InitialSchema
    

    Upon running the command, if you navigate to the Explorer tab, you'll observe that several new files have been generated in the Migrations directory.

    Each of these files plays a crucial role in managing your database schema changes:

    _InitialSchema.cs:

    This file is pivotal to the migration process, containing the Up and Down methods. These methods outline the exact changes to be applied to or reverted from your database schema.

    You'll find yourself engaging with this file frequently to tailor migrations to your specific needs. The Up method details steps to modify the database schema, while the Down method specifies how to undo those changes, ensuring safe and reversible schema evolution.

    _InitialSchema.Designer.cs:

    This file is packed with metadata and a model snapshot utilized by EF Core to orchestrate migrations. It captures the state of your model and the corresponding database schema at the moment of migration, aiding EF Core in accurately tracking changes and managing future migrations.

    LibraryContextModelSnapshot.cs:

    Representing the latest state of your model post-migration, this snapshot file is instrumental for EF Core. It enables the framework to intelligently determine and generate only the necessary schema updates as your model progresses, streamlining the migration process as your application evolves.

    By understanding the purpose and functionality of these files, you'll gain deeper insights into how EF Core manages migrations, setting a solid foundation for effective database schema versioning and modification.

    Naming Convention Proper naming of migrations is crucial for maintaining an organized and readable codebase, especially as your project evolves and accumulates numerous migrations. Here are some key considerations to keep in mind when naming your migrations:

    Avoid Spaces: Migration names should not include spaces. Spaces can lead to confusion and issues with command-line tools and scripts.

    Case Convention: Stick to using either PascalCase or snake_case for naming migrations. Consistency in case convention helps in maintaining readability and order in your migration files.

    Timestamp Prefix: Notice that the EF Core tooling automatically prefixes each migration name with a timestamp. This timestamp ensures that migrations are listed in chronological order, providing a clear timeline of schema changes over time.

    By adhering to these simple yet effective naming conventions, you ensure that your migrations remain well-organized, making it easier for you and your team to navigate and manage database schema changes.

    2️⃣ Initialize the Database With EF Core Migrations set up, you're now ready to recreate the database under the management of EF Core Migrations.
    dotnet ef database update
    

    Executing the database update command leads to several key outcomes:

    Database Creation

    First, the most immediate result is the creation of the library.sqlite file, which you can observe in the Explorer tab.

    This file represents your database, now managed by EF Core Migrations.

    Configurations If you're wondering why the database file is named **library.sqlite**, the answer lies in the configuration settings within your project.

    For this project, you can find the configuration in the LibraryContext.cs file, where the database type and connection are defined.

    Open /Data/LibaryContext.cs file. It's important to note that in some application types, such as ASP.NET Core, this database configuration might be located in the Program.cs file or another configuration file specific to the project's setup.

    This flexibility allows for centralized or context-specific configuration depending on the application's architecture and requirements.

    **EF Core Migration Table**

    Another key outcome of initializing EF Core Migrations is the creation of the __EFMigrationsHistory table. This table plays a critical role in the migration process by tracking the migration history of your database.

    To confirm the creation of this table, alongside the Books table, you can execute the following command:

    sqlite3 library.sqlite .tables
    

    The __EFMigrationsHistory table is designed with simplicity in mind, yet it fulfills an essential function. It stores the names of all migrations that have been applied to the database, along with the specific version of EF Core Migrations that was used for each.

    With your database now under the management of EF Core Migrations, you're ready to further evolve your entity model. Click the right arrow to dive into managing changes to your entity model.

  4. Challenge

    Managing Changes

    Managing Changes

    With the project now successfully transitioned to EF Core Migrations and your database initialized accordingly, you're ready to continue evolving your project's entity model.

    You can move forward with the assurance that your saved data will be maintained throughout the development and deployment process.

    1️⃣ Changing the Entity Model The next step in evolving the LMS project involves enriching the Book entity with additional information. Specifically, you're going to add a `Summary` of the book to provide readers with a brief overview of its contents.

    First, open the /Shared/Book.cs file to modify the Book class: Open the /Shared/Books.cs file.

    Within this file, after the other properties, add a new string property named Summary. This string property will store a concise description or overview of the book.

    public string Summary { get; set; }
    
    2️⃣ Adding a Migration With the entity model updated to meet the current requirements, it's time to create the next migration. You'll use the same `add` command as you did previously to register these changes in your database scheme.

    Execute the following command in the Terminal

    dotnet ef migrations add AddBookSummary
    

    After running this command, navigate to the Explorer tab. There, you'll find a new set of files within the /Migrations directory. One of the these files, named <ts>_AddBookSummary.cs, contains the code to implement this latest migration.

    Opening this file, you can examine how it compares to the InitialSchema migration.

    You'll notice that the AddBookSummary migration Specifically adds a new column to the existing table, in contrast to the InitialSchema migration, which focused on creating the table itself based on the entity's state at that time. This highlights the incremental nature of migrations, allowing each one to build upon the last, step by step, as your model evolves.

    While this example illustrates a straightforward addition of a single property, remember that EF Core Migrations are capable of handling any number of model changes simultaneously.

    However, for the sake of clarity and maintainability, it's advisable to keep you migrations focused and manageable. Ideally, consider scoping each migration to a specific set of related changes or a particular feature. This approach helps keep you project organized and makes it easier to track the history of your database schema over time.

    3️⃣ Apply the Migration Now that your new migration has been created, it's time to apply it to your database, ensuring that the schema reflects the recent changes made to your model.

    Use the same update command as you did previously:

    dotnet ef database update
    

    This command initiates the application of the latest migration, adjusting your database schema to include the new Summary column in the Books table.

    To confirm the addition of this column to the Books table, you can execute the following command:

    sqlite3 library.sqlite ".schema Books"
    

    Remember, while it's a good practice to apply migrations as they are created to keep your development environment up to date, EF Core's tooling is designed with flexibility in mind. It can intelligently apply any number of pending migrations in sequence to transition your database schema to the latest state.

    Congratulations on successfully completing your first database schema migration and making changes to the initial schema!

    Remember, migrations might not always proceed as smoothly as this one, and there may be occassions when you need to make corrections or adjustments.

    Click the right arrow to explore how to effectively revert a migration that requires modification.

  5. Challenge

    Reverting Migrations

    Reverting Migrations

    Throughout the development cycle, it's common to encounter moments when additional changes to your database schema become necessary. Whether these adjustments stem from new requirements or refinements to exisitng features, managing them effectively is key to maintaining a clean and coherent migrations history.

    While one straightforward approach is to create a new migration for each change, there are situations where you might prefer to group related entity changes together for clarity and simplicity. In such cases, EF Core offers a set of commands designed to assist you in managing these changes.

    1️⃣ Listing Migrations It's not uncommon to lose track of whether the latest migration has been applied to your database, especially in active development environments. To quickly ascertain the status of your migrations, EF Core offers a simple yet powerful `list` command: ```bash dotnet ef migrations list ``` Executing this command will display a list of all migrations in your project, clearly indicating which ones have been applied to your database.

    Migrations awaiting application will be marked as (Pending), making it easy for you to identify any updates that need to be applied to keep your database in sync with the entity model.

    2️⃣ Revert Database Migration If you've applied the `AddBookSummary` migration to your database but need to undo this change, reverting to a previous migration state is necessary. This process is straightforward with EF Core's `database update` command, where you specify the migration you want to revert back to. If you wish to revert to the state before `AddBookSummary` was applied, you would target the `InitialSchema` migration.

    Execute the following command to revert the changes made by AddBookSummary

    dotnet ef database update InitialSchema
    

    This action invokes the Down method in the <ts>_AddBookSummary.cs migration file, effectively rolling back the changes made by the migration.

    After reverting, you can verify the status of your migrations with the list command. The AddBookSummary migration should now appear as (Pending), indicating that it is no longer applied to your database.

    Should you need to revert your database to its original state before any migrations were applied, EF Core provides a simple solution. By passing 0 to the database update command, you can roll back all migrations.

    dotnet ef database update 0
    
    3️⃣ Remove Last Migration After successfully reverting the `AddBookSummary` migration in your database, you're now in a position to remove this migration from your project entirely. This step is crucial if you're looking to undo changes or correct mistakes in your migration before reapplying it. To remove the most recently added migration, use the following command: ```bash dotnet ef migrations remove ``` This command tells EF Core to delete the last migration file, effectively removing any trace of the `AddBookSummary` migration from your project.

    To confirm the removal, you can use the list command again.

    4️⃣ Modify Entity Model You are now ready to update your entity model for the required changes. For example, you might need to add a `YearPublished` property alongside the `Summary`. Open **/Shared/Books.cs** file and add the property: ```c# public int YearPublished { get; set; } ```
    5️⃣ Create New Migration With your model now updated to include all required changes, it's time to generate the new migration. This migration will now capture all changes this feature in one migration file. It's a good practice to choose a name for your migration that clearly represents the changes it encompasses. For instance, since you're adding several properties to the `Book` entity, a name like `AddBookDetails` may be more descriptive. ```bash dotnet ef migrations add AddBookDetails ```

    Congratulations on modifying your migration history to more accurately reflect the feature changes as they have occurred.

    To explore further enhancements to your project and deepen your understanding of EF Core's capabilities, please click the right arrow.

  6. Challenge

    7. Next Steps

    Congratulations! You have successfully integrated EF Core Migrations into your project and acquired valuable skills for managing your database schema as your project's entity model evolves.

    You are encouraged to continue refining this project's entity model and migration files. Practicing will further solidify your understanding and proficiency with the skills you have learned.

    This lab has introduced the fundamental capabilities of EF Core Migrations. However, as you delve deeper into using this tool, you'll encounter more complex scenarios that may require leveraging advanced features.

    Some recommendations for next steps in you learning journey:

    Custom Migration Operations:
    EF Core automatically generates Up and Down methods to facilitate database schema management. However, specific scenarios, like renaming a property, might necessitate custom modifications to these methods to prevent data loss. Such as implementing a custom SQL script to rename a column instead of dropping and recreating it.

    Migration Scripts:
    While the database update command is convenient for development cycles, deploying changes to a production database often demands a more controlled approach. EF Core enables you to generate SQK migration scripts, offering a meticuous method for applying migrations in production environments.

    Complex Model Mapping:
    Beyond simple entities, EF Core supports intricate mapping types, accomodating a wide range of entity relationships and schema configurations.

    Different Database Providers:
    This lab focused on SQLite, but EF Core is compatabile with numerous database providers. Each provider may introduce unique migration nuances, so it's important to familiarize yourself with the specific features and limitations of your chosen provider.

    As you continue your journey with EF Core, the depth of you expertise will grow, enabling you to tackle increasingly sophisticated data management challenges. Looking forward to seeing the innovative applications you wil develop with the powerful tools provided by EF Core Migrations.

    Best wishes as you advance in your EF Core learning journey.

About the author

Jeff Hopper is a polyglot solution developer with over 20 years of experience across several business domains. He has enjoyed many of those years focusing on the .Net stack.

Real skill practice before real-world application

Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.

Learn by doing

Engage hands-on with the tools and technologies you’re learning. You pick the skill, we provide the credentials and environment.

Follow your guide

All labs have detailed instructions and objectives, guiding you through the learning process and ensuring you understand every step.

Turn time into mastery

On average, you retain 75% more of your learning if you take time to practice. Hands-on labs set you up for success to make those skills stick.

Get started with Pluralsight