- Lab
-
Libraries: If you want this lab, consider one of these libraries.
- Core Tech
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 Info
Table of Contents
-
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
ChangeTrackercomponent and how it is used to track application entities, detecting changes as those entity properties are modified.EntityEntry
Specifically, exploring the
ChangeTracker's use ofEntityEntrycomponents for each object to track the state changes to the entity, and how theseEntityEntryobjects 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 runOr you can also push the
dotnet runbutton.Each command maps directly to the methods that are available in the **TrackingDemo.cs
** file.To execute the
AddEntity()method, you can append the-- addcommand, such as:dotnet run -- addNote: The
--tellsdotnetto 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.
-
Challenge
Explore EF Core's ChangeTracker
Explore EF Core's ChangeTracker
In this step, you will explore why EF Core's
ChangeTrackercomponent 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
ChangeTrackersteps 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
ChangeTrackerin EF Core keeps track of model changes using individualEntityEntryobjects.Each
EntityEntryobject corresponds to a domain model being tracked by the customDbContext.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
DbSetcollections ofBooksandAuthors. By defining these collections, theLibraryContextbecomes aware that it needs to manage these objects.This
LibraryContextcan 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 theDbContext.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 individualEntityEntrycomponents.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
EntityEntryobject.To achieve this, EF Core provides its own
DebugViewhelper, which can output these details. With the option to either retrieve the fullLongViewdetails or a condensedShortView. 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, andStateproperties.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
EntityEntryobjects.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. Changevar entityEntriesto 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 theDebugViewavailable from theChangeTracker. 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 theAddEntity()method, you'll see theChangeTracker()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 ofPrintEntry()andPrintTracker()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 newLibraryContextinstance is created. Since this is a command-line application, each call from the CLI will create a new instance ofLibraryContext. Therefore, every time thisChangeTracker()method is called, it will display what theLibraryContextis 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
ChangeTrackerdirectly, except for the one call on theauthorEntry. The reason will be explained in a moment.To explore what EF Core is "seeing", you can run the
dotnet run -- ctcommand, which will invoke theChangeTracker()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
DbContextuntil they are explicity made known to the context.In the case of the new
Authorobject, observe both of thenumber of changes:0reports. This demonstrates that theChangeTrackerhas not yet begun tracking this entity.To observe the actual state of this entity, an
EntityEntryinstance is created by callingcontext.Entry(). This creates anEntityEntryfor the newauthorobject. When the state ofauthorEntryis printed, seen under theState of the new Objectlabel, you can see that this entry is in aDetachedstate.It will be in that state until it is added to the
Authorscollection. Only then does the object become attached and EF Core is able to identify it with theAddedstate.Added Status
When the new
Authoris added to the collection, observe that the correspondingEntityEntrydisplays a status ofAdded.Additionally, note that this
Addedentity has an unusualIdvalue and is marked asTemporary.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
EntityEntryhas been reset back to anUnchanged.Also, take note that the previous
Temporarystate of theIdproperty has been replaced with an actual identifier number.Press the right arrow button to explore the
EntityEntrycomponent. -
Challenge
Managing Entity Changes
Managing Entity Changes
You have seen how EF Core uses the
ChangeTrackerto 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
EntityEntryrepresentation 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 firstAuthorinstance 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
DbContextalso 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
EntityEntryand calling thePrintEntry()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 -- modifywill show that this entity has a state ofUnchangedmeaning 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 theFirstName:author.FirstName = "Dave"; authorEntry.PrintEntry("Property Changed");Rerunning the Terminal command
dotnet run -- modifywill show that theEntityEntryis still marked asUnchanged, even though theFirstNameproperty has changed. This is because theEntityEntryis 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 callingSaveChanges(), EF Core callsDetectChanges(). TheDetectChanges()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 theEntityEntrytoModified.To see this in action, manually call the context's
DetectChanges()method. Right after the lastauthorEntry.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 asModified.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 -- modifycommand will show that once the changes are saved, the property value is updated, and the entity's status is set back toUnchanged.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 asUnchanged.This is because, even though the code is setting the
FirstNameproperty, it's being set to the same value, which is not recognized as a change byDetectChanges.To rerun this scenario you'll need to change the
FirstNameto 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
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.