TrackableEntities.EF.Core
3.0.0
See the version list below for details.
dotnet add package TrackableEntities.EF.Core --version 3.0.0
NuGet\Install-Package TrackableEntities.EF.Core -Version 3.0.0
<PackageReference Include="TrackableEntities.EF.Core" Version="3.0.0" />
paket add TrackableEntities.EF.Core --version 3.0.0
#r "nuget: TrackableEntities.EF.Core, 3.0.0"
// Install TrackableEntities.EF.Core as a Cake Addin #addin nuget:?package=TrackableEntities.EF.Core&version=3.0.0 // Install TrackableEntities.EF.Core as a Cake Tool #tool nuget:?package=TrackableEntities.EF.Core&version=3.0.0
Trackable Entities for Entity Framework Core
Change-tracking across service boundaries with ASP.NET Core Web API and Entity Framework Core.
What is Trackable Entities?
Trackable Entities allows you to mark client-side entities as Added, Modified or Deleted, so that entire object graphs can be sent to a service where changes can be saved with a single round trip to the server and within a single transaction.
Installation
Trackable Entities for EF Core is available as a NuGet package that can be installed in an ASP.NET Core Web API project that uses Entity Framework Core.
You can use the Package Manager UI or Console in Visual Studio to install the TE package.
install-package TrackableEntities.EF.Core
You can also use the .NET Core CLI to install the TE package.
dotnet add package TrackableEntities.EF.Core
Trackable Entities Interfaces
The way Trackable Entities allows change-tracking across service boundaries is by adding a TrackingState
property to each entity. TrackingState
is a simple enum with values for Unchanged
, Added
, Modified
and Deleted
. The TE library will traverse objects graphs to read this property and inform EF Core of each entity state, so that you can save all the changes at once, wrapping them in a single transaction that will roll back if any individual update fails.
TrackingState
is a member of the ITrackable
interface, which also includes a ModifiedProperties
with the names of all entity properties that have been modified, so that EF Core can perform partial entity updates.
In order for clients to merge changed entities back into client-side object graphs, TE includes an IMergeable
interface that has an EntityIdentifier
property for correlating updated entities with original entities on the client. The reason for returning updated entities to the client is to transmit database-generated values for things like primary keys or concurrency tokens.
Each tracked entity needs to implement ITrackable
, as well as IMergeable
, either directly or in a base class. In addition, properties of these interfaces should be decorated with a [NotMapped]
attribute so that EF Core will not attempt to save these to the database. For example, a Product
entity might look like this:
public class Product : ITrackable, IMergeable
{
public int ProductId { get; set; }
public string ProductName { get; set; }
public decimal? UnitPrice { get; set; }
[NotMapped]
public TrackingState TrackingState { get; set; }
[NotMapped]
public ICollection<string> ModifiedProperties { get; set; }
[NotMapped]
public Guid EntityIdentifier { get; set; }
}
Server-side trackable entities can either be writen by hand or generated from an existing database using code-generation techniques. Trackable Entities provides CodeTemplates NuGet packages which add T4 templates to a traditional .NET class library for generating trackable entities using the Visual Studio wizard for adding an ADO.NET Entity Data Model. You can then add a NetStandard class library which links to the generated entities. See the TE Core Sample project for an example of how to do this.
Note: The reason for the extra project with generated entities is that EF Core does not yet support customizing scaffolded models for server-side entities. We will provide code generation packages for Trackable Entities as soon as EF Core tooling is updated to support customization.
Usage
For an example of how to use Trackable Entities for EF Core in an ASP.NET Core Web API, have a look at OrderContoller in the sample app, which includes GET, POST, PUT and DELETE actions. GET actions don't inlude any code that uses Trackable Entities, but the other actions set TrackingState
before calling ApplyChanges
on the DbContext
class and then saving changes.
// Set state to added
order.TrackingState = TrackingState.Added;
// Apply changes to context
_context.ApplyChanges(order);
// Persist changes
await _context.SaveChangesAsync();
After saving changes, LoadRelatedEntitiesAsync
is called in order to populate reference properties for foreign keys that have been set. This is required, for example, in order to set the Customer
property of an Order
that has been added with a specified CustomerId
. This way the client can create a new Order
without populating the Customer
property, which results in a smaller payload when sending the a new order to the Web API. Loading related entities then populates the Customer
property before returning the added order to the client.
// Populate reference properties
await _context.LoadRelatedEntitiesAsync(order);
Lastly, you should call AcceptChanges
to reset TrackingState
on each entity in the object graph before returning it to the client, so that the client can then make changes to the object and send it back to the Web API for persisting those changes.
// Reset tracking state to unchanged
_context.AcceptChanges(order);
Questions and Feedback
If you have any questions about Trackable Entities, would like to request features, or discover any bugs, please create an issue on the GitHub repository. If you wish to contribute to Trackable Entities, pull requests are welcome!
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.1 is compatible. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- Microsoft.EntityFrameworkCore (>= 3.0.0)
- TrackableEntities.Common.Core (>= 3.0.0)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on TrackableEntities.EF.Core:
Package | Downloads |
---|---|
URF.Core.EF.Trackable
This official URF framework minimizes the surface area of your ORM technlogy from disseminating in your application. Framework provides an elegant way to implement a reusable and extensible Unit of Work and Repository pattern. |
|
afrikancoder-shared
Functionality shared across bounded contexts in the AfrikanCoder project |
GitHub repositories (1)
Showing the top 1 popular GitHub repositories that depend on TrackableEntities.EF.Core:
Repository | Stars |
---|---|
urfnet/URF.Core
Unit of Work & Repositories Framework - .NET Core, NET Standard, Entity Framework Core. 100% extensible & lightweight.
|
Version | Downloads | Last updated |
---|---|---|
8.0.0 | 15,918 | 2/18/2024 |
7.0.0 | 18,082 | 2/19/2023 |
6.0.0 | 56,931 | 2/7/2022 |
5.0.1 | 43,369 | 11/24/2020 |
5.0.0 | 1,669 | 11/24/2020 |
3.1.1 | 8,119 | 11/24/2020 |
3.1.0 | 42,518 | 3/9/2020 |
3.0.0 | 6,781 | 10/14/2019 |
3.0.0-preview7 | 447 | 8/12/2019 |
1.2.0 | 48,451 | 1/13/2019 |
1.1.0 | 23,754 | 5/30/2018 |
1.0.0 | 2,097 | 5/21/2018 |
1.0.0-rc | 2,183 | 2/5/2018 |
1.0.0-beta | 2,383 | 9/27/2017 |
1.0.0-alpha | 1,420 | 9/27/2017 |