It’s here! Trackable Entities for EF Core!

The idea behind my open source Trackable Entities project is quite simple: track changes to an object graph as you update, add and remove items, then send those changes to a back end service where they can be saved in a single transaction.  It’s an important thing to be able to do, because it’s difficult to wrap multiple round trips in a single transaction without holding locks for a long time.  On the other hand, you could break up related operations into multiple transactions, but then you lose the benefit of atomicity, which enables you to roll back all the changes in a transaction should one of them fail.

To get started with Trackable Entities for Entity Framework Core, download the NuGet package and check out the project repository.  You can also clone the sample applications and follow the instructions.

Brief Introduction

For example, you update an order with related details.  Some details are unchanged, while others are modified, added or removed.  All these changes should be atomic, that is, they should all succeed or none.  The problem with regard to Entity Framework is that, in the context of a web service, updates must be conducted in a disconnected manner, which means that you need to inform EF about which entities require updating and what kind of changes it needs to perform.  In the case of an order with multiple details that need to be updated all at once, there needs to be a way to communicate this information to the web service so that you can attach entities to a DbContext and individually set the state of each entity.  The way Trackable Entities accomplishes this is by means of a simple enum called TrackingState.

public enum TrackingState

To track changes, entities implement an ITrackable interface, which includes a ModifiedProperties property to support partial updates.

public interface ITrackable
TrackingState TrackingState { get; set; }
ICollection<string> ModifiedProperties { get; set; }
view raw ITrackable.cs hosted with ❤ by GitHub

In addition, Trackable Entities provides an IMergeable interface to correlate updated entities so they can be merged back into the original object graph on the client.

public interface IMergeable
Guid EntityIdentifier { get; set; }
view raw IMergeable.cs hosted with ❤ by GitHub

Once entities have been marked as Added, Modified or Deleted, all you have to do is call the ApplyChanges extension method for DbContext.

// Inform EF about changes in an object graph
// Persist all changes in a single transaction
view raw ApplyChanges.cs hosted with ❤ by GitHub

Trackable Entities for EF Core

Because Trackable Entities is an extension of Entity Framework, it has only been available for the full .NET Framework running on Windows.  But now that EF has been ported to .NET Core and can run on Linux and MacOS, it’s time for Trackable Entities to come along for the ride!  This makes it possible to create a Web API with ASP.NET Core that can run both locally on a Mac and in a Docker container running on a Linux VM in the Cloud.  How cool is that?!

To get started you can either use Visual Studio for Windows, Visual Studio for Mac, or if you’re adventurous, Visual Studio Code.  It doesn’t matter which option you choose, because in the end your web app will run anywhere .NET Core will run.  In this blog post I’ll walk you through a demo using VS for Mac — just for fun.  But if you prefer, feel free to check out the sample I created using the “classic” version of Visual Studio on Windows.

Note: You’ll need to install the SDK for .NET Core 2.0 or higher.

Start by creating a new project in VS using the ASP.NET Core Web API project template.


Then add a .NET Standard Class Library for server-side trackable entities.


Add the TrackableEntities.Common.Core (pre-release) and System.ComponentModel.Annotations NuGet packages.


Add classes that implement ITrackable and IMergeable interfaces. You’ll also need to add a using directive for System.ComponentModel.DataAnnotations.Schema, so that you can decorate TrackingState, ModifiedProperties and EntityIdentifier properties with a [NotMapped] attribute, to indicate these properties do not belong to the database schema.

public class Product : ITrackable, IMergeable
public int ProductId { get; set; }
public string ProductName { get; set; }
public int? CategoryId { get; set; }
public decimal? UnitPrice { get; set; }
public bool Discontinued { get; set; }
public byte[] RowVersion { get; set; }
public Category Category { get; set; }
public TrackingState TrackingState { get; set; }
public ICollection<string> ModifiedProperties { get; set; }
public Guid EntityIdentifier { get; set; }
view raw Product.cs hosted with ❤ by GitHub

EF Core Migrations

Although it is possible to generate entities based on database tables (Database First), in this demo we’ll go the other way and start with entities that will be used to generate database tables and relationships (Code First).  Both approaches use the EF .NET Core CLI, which you install by adding the Microsoft.EntityFrameworkCore.Design package and manually editing the .csproj file for the Web API project to insert a DotNetCliToolReference and change the project target from netstandard2.0 to netcoreapp2.0 (which is required to run the EF CLI). You’ll also need to add a package for the EF provider you’re using, which in this case is Microsoft.EntityFrameworkCore.Sqlite, as well as a reference to the server-side entities project you created earlier.  Then run dotnet restore from the command line.  (Visual Studio does not yet automatically restore tooling packages.)  Here is what your .csproj file will then look like.

<Project Sdk="Microsoft.NET.Sdk.Web">
<Folder Include="wwwroot\" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.0" />
<PackageReference Include="TrackableEntities.EF.Core" Version="1.0.0-beta" />
<DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" />
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
<ProjectReference Include="..\TrackableEntities.Core.Sample.XPlat.Entities.WebApi\TrackableEntities.Core.Sample.XPlat.Entities.WebApi.csproj" />

Next, add a specific DbContext-derived class to the Web API project.

public class NorthwindSlimContext : DbContext
public NorthwindSlimContext(DbContextOptions<NorthwindSlimContext> options) : base(options) { }
public DbSet<Category> Categories { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<OrderDetail> OrderDetails { get; set; }
public DbSet<Product> Products { get; set; }

Lastly, you’ll need to add a class that implements IDesignTimeDbContextFactory to create your context class with the appropriate options and connection string.

public class NorthwindSlimContextFactory : IDesignTimeDbContextFactory<NorthwindSlimContext>
public NorthwindSlimContext CreateDbContext(string[] args)
var optionsBuilder = new DbContextOptionsBuilder<NorthwindSlimContext>();
optionsBuilder.UseSqlite("Data Source=northwindslim.db");
return new NorthwindSlimContext(optionsBuilder.Options);

Now all you need to do to create a database from your entities is to execute the following two commands, after which a northwindslim.db file will appear in the project directory.

dotnet ef migrations add initial
dotnet ef database update

Configure Dependency Injection

To inject your EF context class into controllers, you’ll need to register it with ASP.NET Core’s dependency injection system.  Add code to the ConfigureServices method of the Startup class in which you call services.AddDbContext, passing options that include the provider and connection string.  You’ll also want to configure the JSON serializer to preserve references in order to accommodate cyclical references in object graphs.

public void ConfigureServices(IServiceCollection services)
options => options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.All);
options => options.UseSqlite("Data Source=northwindslim.db"));

Web API Controllers

Next add the TrackableEntities.EF.Core NuGet package to the Web API project.  Then you can add a controller to the project in which you use LINQ to execute queries against the database and return objects from your GET actions.

public class CustomerController : Controller
private readonly NorthwindSlimContext _context;
public CustomerController(NorthwindSlimContext context)
_context = context;
// GET: api/Customer
public async Task<IActionResult> GetCustomers()
var customers = await _context.Customers
return Ok(customers);
// GET: api/Customer/ALFKI
public async Task<IActionResult> GetCustomer([FromRoute] string id)
var customer = await _context.Customers.SingleOrDefaultAsync(m => m.CustomerId == id);
if (customer == null)
return NotFound();
return Ok(customer);

Then to utilize Trackable Entities for persisting object graphs with changed entities, all you need to do is call context.ApplyChanges.

// PUT: api/Order
public async Task<IActionResult> PutOrder([FromBody] Order order)
// Apply changes to context
// Persist changes
await _context.SaveChangesAsync();
catch (DbUpdateConcurrencyException)
if (!_context.Orders.Any(o => o.OrderId == order.OrderId))
return NotFound();
// Populate reference properties
await _context.LoadRelatedEntitiesAsync(order);
// Reset tracking state to unchanged
// Return updated order
return Ok(order);

Note that after calling context.SaveChangesAsync() there is a line of code that calls context.LoadRelatedEntitiesAsync, passing the root entity.  This will traverse the object graph, loading reference properties so that entities returned to the client will have them populated.  For example, when updating an Order it isn’t necessary to send the entire Customer entity when all you have to do is set the order’s CustomerId property.  But the client will usually want to have the Customer property populated when it is returned from the service, which is what LoadRelatedEntitiesAsync does. Lastly, the call to context.AcceptChanges is there to reset TrackingState on each entity to Unchanged, so that the client can can have a fresh start before making additional changes.

You can now execute dotnet run on the command line and the Web API will start listening for requests on the default port 5000.


You can then open a browser and navigate to an API endpoint to make sure you can retrieve entities.  You can also use a REST client such as Postman to make POST, PUT and DELETE requests.


Trackable Entities on the Client

On the client side Trackable Entities provides change-tracking for .NET apps by means of a ChangeTrackingCollection.  You can create a .NET Core console app to which you can add the TrackableEntities.Client NuGet package. Even though this package was written for the full .NET Framework version 4.6.1, you can use it in a .NET Core app because both are compliant with .NET Standard 2.0.

Because client-side entities have a different set of concerns than server-side entities, firing events on property changes and using change tracking collections for navigation properties, you’ll probably want to generate client entities from the database schema you created earlier using the EF Core CLI tooling.  The easiest way to accomplish this is to use T4 templates.  Fortunately, Trackable Entities has a package for that — TrackableEntities.CodeTemplates.Client.Net45.  You’ll need to add it to a traditional .NET Class Library project in Visual Studio for Windows, so that you can add an ADO.NET Entity Data Model that will use it to generate the client entities.

You can then write client-side code that changes entities, gets only the changed entities, and sends them to your Web API service for applying changes and saving them to the database.  See the sample app’s repository for the complete code.

To run the console app, keep the Web API running and execute dotnet run.  Follow the prompts to retrieve, add, update and delete entities at various places in the object graph.


The cool thing is that all this is happening on a Mac, and there’s nothing to stop you from deploying it to a container service such as Amazon EC2, Microsoft Azure or Google Container Engine.  With Trackable Entities and EF Core the future is now.

About Tony Sneed

Sr. Software Solutions Architect, Hilti Global Application Software
This entry was posted in Technical and tagged , , , . Bookmark the permalink.

3 Responses to It’s here! Trackable Entities for EF Core!

  1. Dot Net says:

    It is a great experience to read your blog on Trackable Entities for EF Core. It is a great source of information for the confused minds. today i learn new thing about EF core. Thank you for sharing such an informative blog.

  2. Dot Net Amateur says:

    This appears to be exactly what I am looking for. I have some prior experience with Entity Framework using the .NET Framework (note Core), and recall that it “magically” handled the scenario where a parent has child objects which may be added, removed or updated, and saving with one call which handles all of these

    That being said, it looks like there are a lot of modifications required to achieve the functionality mentioned above, and if we have an existing EF Core API project with existing models/controllers, this may be difficult to implement. As a result, I am having a bit of difficulty following the steps required to get this working, as we are using EF Core and OData Core and some of the steps in the README are a bit difficult to follow as I am not a black-belt developer.

    Shouldn’t this behaviour be something that is part of EF Core natively?

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.