Assuming you have defined a shadow property LastModified
for each entity you want that functionality as in your example
builder.Property<DateTime>("LastUpdated");
and the question is how to update it automatically.
The technique described in the David's answer is outdated. It's still possible to override SaveChanges
(and SaveChangesAsync
), but there is IMHO a better approach, shown in Populate Created and LastModified automagically in EF Core. It's interface based approach, but can easily be adjusted for shadow property (or any property - the methods used work for both shadow and explicit properties).
Quick recap: Starting with v2.1, EF Core provides State change events:
New Tracked
And StateChanged
events on ChangeTracker
can be used to write logic that reacts to entities entering the DbContext
or changing their state.
Here is how you can utilize them. Add the following to your derived context class:
void SubscribeStateChangeEvents()
{
ChangeTracker.Tracked += OnEntityTracked;
ChangeTracker.StateChanged += OnEntityStateChanged;
}
void OnEntityStateChanged(object sender, EntityStateChangedEventArgs e)
{
ProcessLastModified(e.Entry);
}
void OnEntityTracked(object sender, EntityTrackedEventArgs e)
{
if (!e.FromQuery)
ProcessLastModified(e.Entry);
}
void ProcessLastModified(EntityEntry entry)
{
if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
{
var property = entry.Metadata.FindProperty("LastModified");
if (property != null && property.ClrType == typeof(DateTime))
entry.CurrentValues[property] = DateTime.UtcNow;
}
}
and add
SubscribeStateChangeEvents();
to your derived context constructor(s).
And that's all. Once the context is subscribed to these events, it will be notified anytime the entity is initially tracked or its state changes. You are interested only with Modified
and Added
state not triggered by query materialization (if you don't need Added
, then just exclude it from the if
condition). Then you check if the entity contains DateTime LastModified
property using the EF Core metadata services and if yes, simply update it with the current date/time.