Interview question
Expire sessions with ExecuteUpdateAsync
Performs a set-based bulk update without loading session entities into the change tracker.
TL;DR
Performs a set-based bulk update without loading session entities into the change tracker.
ExecuteUpdateAsync, set-based updates, affected-row counts, cancellation, and change-tracker bypass behavior.
Practice the problem like a real interview: restate, reason, implement, and test.
Entity: Session(Id, ExpiresAtUtc, IsExpired, ExpiredAtUtc). Update rows where IsExpired is false and ExpiresAtUtc <= now. Return the number of rows affected. Do not load sessions first.
Next in EF Core Labs: Rowversion Conflict
Ten expired active sessions are updated by one SQL command and the method returns 10. Already-expired and future sessions are unchanged.
now once before building the query.ExecuteUpdateAsync.I express both the target set and assigned values in the database command. ExecuteUpdateAsync bypasses entity materialization, change detection, and SaveChanges. That is ideal for a set-based maintenance operation, but any matching entities already tracked in the same context become stale.
public static Task<int> ExpireSessionsAsync(
AppDbContext db,
DateTimeOffset now,
CancellationToken cancellationToken)
{
return db.Sessions
.Where(session =>
!session.IsExpired &&
session.ExpiresAtUtc <= now)
.ExecuteUpdateAsync(
setters => setters
.SetProperty(session => session.IsExpired, true)
.SetProperty(session => session.ExpiredAtUtc, now),
cancellationToken);
}
The provider emits one conditional UPDATE and returns the affected-row count. An index supporting active sessions by expiry can reduce the scanned set. Entity interceptors and per-entity domain methods do not run, so this technique belongs only where set-based semantics are intentional.
now.SaveChangesAsync as if ExecuteUpdate used the tracker.Spot a weak answer, missing edge case, or clearer explanation? Send it in.