Change tracking, and a gotcha you'd trust
When you DO update an existing entity (rather than append), Fusion prefers EF’s change tracking over hand-rolled bulk updates. The repository loads a tracked entity, the aggregate mutates its state, and SaveChangesAsync writes the diff. The anti-pattern is reaching for ExecuteUpdateAsync with a .Where(...) clause that re-encodes a domain predicate, because then the same rule lives in two places: the aggregate and the SQL WHERE.
Now a gotcha that’s worth the whole lesson, because it’s the kind of thing you’d read and trust. The FlightNote DBO has audit columns (CreatedBy, CreatedDateTimeUtc) filled by Postgres defaults (current_user, now()) on INSERT. It’s tempting to read CreatedBy as “the operator who wrote the note.” It is not.
This is the deeper habit the course is really teaching: read the code AND its comments for what’s actually guaranteed, not what a name implies. A column called CreatedBy implies user attribution; the comment and the convention tell you it’s the DB account. The reviewers who wrote these anti-patterns learned them the same way, one surprising PR at a time.
Try it yourself
Change tracking over ExecuteUpdate
Convention D3, stated.
When updating an existing entity, why does Fusion prefer loading a tracked entity and calling SaveChangesAsync over an ExecuteUpdateAsync with a .Where(...) predicate?
Reveal answer
Because an ExecuteUpdateAsync WHERE clause tends to re-encode a domain predicate (e.g. "has an active decision"), so the same rule lives in both the aggregate and the SQL. Loading a tracked entity lets the aggregate own the mutation and EF just pushes the diff, keeping the rule in one place (convention D3).
What CreatedBy actually holds
The note DBO's CreatedBy is populated by a Postgres current_user default. Who does it identify?
Show answer
Correct answer: B — The database service account the app connects as
current_user is the DB account the app connects as, not the authenticated operator, and it only stamps on INSERT. Real per-operator attribution was descoped (anti-pattern #35), so never read CreatedBy as user identity without an app-layer capture.