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: Tracking and Saving Data with EF Core

While an application is interacting with the domain model, EF Core is working behind the scenes to track changes. This lab will explore some of the "under the hood" components used by EF Core to help manage these changes.

Lab platform
Lab Info
Level
Intermediate
Last updated
Dec 23, 2025
Duration
30m

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: Tracking and Saving Data with EF Core

    Entity Framework Core (EF Core) is a robust Object-Relational Mapping (ORM) framework that provides .NET developers with a comprehensive suite of tools for efficient database management.

    While an application is interacting with the domain model, EF Core is working behind the scenes to track changes.

    This lab will explore some of the "under the hood" components used by EF Core to help manage these changes.

    Prerequisites ----- This lab assumes you have the following prerequisite knowledge and skills:

    Understanding of EF Core

    A basic understanding of how EF Core works, including the role of the DbContext and DbSet collections and how they are used to interact with a database.

    Basic Database Concepts

    A basic understanding of relation database concepts, such as tables, columns, and primary/foreign keys.

    Objective ----- The objective of this lab is to explore the following topics:

    ChangeTracker

    This lab will explore EF Core's ChangeTracker component and how it is used to track application entities, detecting changes as those entity properties are modified.

    EntityEntry

    Specifically, exploring the ChangeTracker's use of EntityEntry components for each object to track the state changes to the entity, and how these EntityEntry objects are used to monitor and manage the state changes to the entities.

    Note: In EF Core, the term 'Entity' specifically refers to in-memory objects that the DbContext has been made aware of.

    For an object to be managed as an 'Entity', it must have an identifier property that is mapped to the 'Key' column of the related database table."

    In addition, the lab will cover some advanced tooling options for bulk interactions with the database. Learning how EF Core manages entity changes can go a long way to help you better understand how to structure your application and troubleshoot when EF Core is not working quite as expected.

    Project ----- To help you explore the `ChangeTracker` and `EntityEntry` concepts, a simple command line application will be used.

    This application contains several methods that you can use to interact with the EF Core change tracking features. These can be seen by running the following command in the Terminal:

    dotnet run 
    

    Or you can also push the dotnet run button.

    Each command maps directly to the methods that are available in the **TrackingDemo.cs
    ** file.

    To execute the AddEntity() method, you can append the -- add command, such as: dotnet run -- add

    Note: The -- tells dotnet to pass the following parameters to the application.

    Learning Environment ---- Before diving in, take a moment to familiarize yourself with the lab's interface.

    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.

    When ready, press the right arrow button to begin exploring how EF Core manages entity changes.

  2. Challenge

    Explore EF Core's ChangeTracker

    Explore EF Core's ChangeTracker

    In this step, you will explore why EF Core's ChangeTracker component is essential for managing changes to your domain models.

    ChangeTracker Benefits ----- With EF Core, you have the advantage of using Plain Old C# Objects (POCOs) to build your application's domain models.

    This allows you to develop models without the concern of how EF Core will persist these objects to the database.

    However, in order to effectively persist changes, EF Core needs to be aware of modifications made to these models.

    This is where the ChangeTracker steps in. It acts as a monitoring system within EF Core, detecting and keeping track of changes made to entities within your custom context.

    By tracking the state of your entities, EF Core can perform the necessary actions, such as inserting, updating, or deleting records in the database without needing to embed itself into the domain model.

    The ChangeTracker in EF Core keeps track of model changes using individual EntityEntry objects.

    Each EntityEntry object corresponds to a domain model being tracked by the custom DbContext.

    Custom DbContext ----- To efficiently manage the persistence of model changes to the database, EF Core relies on your application's knowledge of the domain. This knowledge is encapsulated and managed by a custom implementation of the `DbContext`.

    For example, take a look at this application's **/Domain/LibraryContext.cs ** file. Specifically, note the DbSet collections of Books and Authors. By defining these collections, the LibraryContext becomes aware that it needs to manage these objects.

    This LibraryContext can then be used within the application to manage changes to these objects, as demonstrated in the **/TrackingDemo.cs ** file.

    In the AddEntity() method, you can observe a simple example of creating a model instance, adding it to the context, and then saving it to the database.

    While this is a straightforward example you are probably very familiar with, its simplicity will help demonstrate what EF Core is aware of and when it becomes aware of it.

    Exploration Helpers -----

    To facilitate exploration, the **TrackingDemo ** class includes a couple Printxxx() extension methods at the bottom. These methods are designed to help you examine and understand the details of the entities being tracked by the DbContext.

    However, to make them more useful for exploring what EF Core is managing at each stage of the process, some modifications are required.

    PrintEntry()

    Reviewing the PrintEntry() helper extension. This method is used to display the details of individual EntityEntry components.

    The first line writes a label to the console to help locate this section in the Terminal.

    The second line writes out the details of the EntityEntry object.

    To achieve this, EF Core provides its own DebugView helper, which can output these details. With the option to either retrieve the full LongView details or a condensed ShortView. The line should now look like:

    Console.WriteLine(entry.DebugView.LongView);
    

    Alternative Implementation

    Alternatively, if you scroll down to the commented-out section, you'll find an alternative approach to manually display these details. It involves directly referencing the OriginalValues, CurrentValues, and State properties.

    Note: The .ToObject() initializes a copy of the stored entity and populates it with either the original or current (changed) values.

    PrintTracker

    Now, scroll down to the PrintTracker() method.

    You can ignore the first label line.

    The next line currently initializes an empty list of EntityEntry objects.

    The purpose of this helper method is to display the details of all entities being tracked.

    You can retrieve all of these entities using the context's ChangeTracker.Entries() method. Change var entityEntries to now be:

    var entityEntries = context.ChangeTracker.Entries();
    

    Next, to provide the details of what is being tracked, similar to PrintEntry(), it would be useful to utilize the DebugView available from the ChangeTracker. This version will iterate through all tracked entities. Add the following line to write out the tracked details:

    Console.WriteLine(context.ChangeTracker.DebugView.LongView);
    

    Now that these helper methods are ready, it is time to start exploring some of what EF Core is doing "under the hood".

    Under the Hood -----

    Returning to the top of the TrackingDemo() file. Just below the AddEntity() method, you'll see the ChangeTracker() method.

    This method contains the exact same lines to create a new Author, add it to the context, and then save those changes. The only difference is the inclusion of PrintEntry() and PrintTracker() calls between each line.

    Here, you will walk through each line of this method:

    The PrintTracker("Fresh Start") call will demonstrate what happens when a new LibraryContext instance is created. Since this is a command-line application, each call from the CLI will create a new instance of LibraryContext. Therefore, every time this ChangeTracker() method is called, it will display what the LibraryContext is aware of when it is initialized.

    Each subsequent step in the ChangeTracker() method will then demonstrate tracking changes at each step of the process.

    Most of these exploration calls are on the ChangeTracker directly, except for the one call on the authorEntry. The reason will be explained in a moment.

    To explore what EF Core is "seeing", you can run the dotnet run -- ct command, which will invoke the ChangeTracker() method.

    Exploring the Results

    Scrolling up in the Terminal window, you should be able to locate the following line:

    ****** ChangeTracker ******
    

    Pro Tip


    Note: Feel free to adjust the height of the Terminal window to see more content.

    Alternatively, you can click the ^ arrow in the upper-right corner of the Terminal to maximize that window.

    To minimize the Terminal screen, click the down arrow.

    Points to Notice

    When Tracking Starts:

    Objects are not automatically tracked by the DbContext until they are explicity made known to the context.

    In the case of the new Author object, observe both of the number of changes:0 reports. This demonstrates that the ChangeTracker has not yet begun tracking this entity.

    To observe the actual state of this entity, an EntityEntry instance is created by calling context.Entry(). This creates an EntityEntry for the new author object. When the state of authorEntry is printed, seen under the State of the new Object label, you can see that this entry is in a Detached state.

    It will be in that state until it is added to the Authors collection. Only then does the object become attached and EF Core is able to identify it with the Added state.

    Added Status

    When the new Author is added to the collection, observe that the corresponding EntityEntry displays a status of Added.

    Additionally, note that this Added entity has an unusual Id value and is marked as Temporary.

    Status After Saved

    Observe that after the context saves the changes, the status is now set to Unchanged.

    Now that EF Core has persisted the changes, the EntityEntry has been reset back to an Unchanged.

    Also, take note that the previous Temporary state of the Id property has been replaced with an actual identifier number.

    Press the right arrow button to explore the EntityEntry component.

  3. Challenge

    Managing Entity Changes

    Managing Entity Changes

    You have seen how EF Core uses the ChangeTracker to manage entities that have been added to the context.

    Changes to entities are handled almost the same, but with one small difference. While EF Core maintains a reference to all entities that it is tracking, it does not actively monitor those entities for changes.

    Instead, it needs to be told when to detect changes and update the EntityEntry representation accordingly.

    The TrackingDemo.ModifyEntry() method has been created to help explore how EF Core manages changes to entities that it is tracking.

    Start Tracking -----

    The ModifyEntry() method starts by retrieving the first Author instance from the database. Since EF Core is retrieving this entity, it is now tracking this entity.

    Other Means of Tracking

    EF Core has several means of becoming aware of entities to track.

    As seen above, entities returned from a query result are tracked.

    Previously seen, new entities are also tracked when added using the context's .Add() method.

    A DbContext also has other similar methods that initiate tracking, such as .Attach() and .Update().

    These are advanced features to help achieve different use cases, such as the disconnected nature of ASP.Net applications.

    In addition to these direct approaches, EF Core will also detect entities that are connected to existing tracked entities.

    This can be seen by retrieving the EntityEntry and calling the PrintEntry() extension method to see the state of the entity. After retrieving the author, add the following lines:

    var authorEntry = context.Entry(author);
    authorEntry.PrintEntry("Retrieved from Context");
    

    In the Terminal, running the command dotnet run -- modify will show that this entity has a state of Unchanged meaning that it is being tracked.

    Note: If it was not being tracked it would show a state of Detached.

    Now, you can make a change to this entity and follow that up with another PrintEntry(). For example, change the FirstName:

    author.FirstName = "Dave";
    authorEntry.PrintEntry("Property Changed");
    

    Rerunning the Terminal command dotnet run -- modify will show that the EntityEntry is still marked as Unchanged, even though the FirstName property has changed. This is because the EntityEntry is maintaining the original and current values, but has not yet been informed to update its state.

    Detecting Changes ----- If you have previous experience with EF Core, you know that calling `SaveChanges()` on this context will apply the changes. The question, however, is what happens between the currently observed `Unchanged` state and the actual saving of the changes. At some point the `EntityEntry` needs to be updated to a `Modified` state.

    The answer to this question lies in the ChangeTracker.DetectChanges() method. Just prior to calling SaveChanges(), EF Core calls DetectChanges(). The DetectChanges() method scans all tracked entities, comparing their current property values against the original property values. If any differences are found, EF Core updates the state of the EntityEntry to Modified.

    To see this in action, manually call the context's DetectChanges() method. Right after the last authorEntry.PrintEntry() call, add the following lines:

    context.ChangeTracker.DetectChanges();
    authorEntry.PrintEntry("DetectChanges");
    

    Rerunning the Terminal command dotnet run -- modify, you will now see that the state of the entry has been marked as Modified.

    Saving Changes ----- Now that EF Core has detected has detected the modification and updated the `EntityEntry` accordingly, the changes can be saved. To save the changes, add the following lines: ```c# context.SaveChanges(); authorEntry.PrintEntry("Changes Saved"); ``` > Note: It's important to remember that `DetectChanges` is one of the first steps that is called as part of `SaveChanges()`.

    Rerunning the dotnet run -- modify command will show that once the changes are saved, the property value is updated, and the entity's status is set back to Unchanged.

    However, if you rerun the command again, you'll observe the state remains Unchanged.

    Additional Observation

    If you rerun dotnet run -- modify, observe that the state stays as Unchanged.

    This is because, even though the code is setting the FirstName property, it's being set to the same value, which is not recognized as a change by DetectChanges.

    To rerun this scenario you'll need to change the FirstName to something different.

    Congratulations on completing this Guided Code Lab! Through your "under the hood" exploration of Entity Framework Core, you've gained valuable insights into how this powerful ORM works under the surface.

    Feel free to continue your exploration in this lab by testing different scenarios and using the print commands to explore.

    Wishing you the best on your continuing 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