Skip to content

Don't clear ChangeTracker on EnsureCreated/Migrate retry; skip seeder if it already ran#38274

Open
Copilot wants to merge 2 commits into
mainfrom
copilot/remove-calling-seeder-twice
Open

Don't clear ChangeTracker on EnsureCreated/Migrate retry; skip seeder if it already ran#38274
Copilot wants to merge 2 commits into
mainfrom
copilot/remove-calling-seeder-twice

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 14, 2026

Follow-up to #38211. Calling ChangeTracker.Clear() from inside EnsureCreated[Async] and Migrate[Async] on retry is too invasive — it wipes user-tracked state as a side effect of a transient failure elsewhere. The original concern (avoiding double-seeding when the execution strategy retries) is better addressed by simply not re-invoking the seeder once it has already completed successfully.

  • CosmosDatabaseCreator.EnsureCreatedAsync: dropped the Retrying flag and the ChangeTracker.Clear() call; added a Seeded StrongBox that gates SeedDataAsync so the async seeder runs at most once across retries.
  • RelationalDatabaseCreator.EnsureCreated / EnsureCreatedAsync: same treatment — removed the retry branch that cleared the change tracker, and short-circuit the execution-strategy callback when Seeded is already set.
  • Migrator.MigrateImplementation / MigrateImplementationAsync: same treatment — removed the retry branch that cleared the change tracker, and skip the seeder when it has already completed. MigrationExecutionState.SeedingAttempted is renamed to SeedingCompleted (and the API baseline updated) to reflect that the flag is only set after a successful seed.

The seeded/completed flag is set only after the seeder (and, for the relational path, the surrounding transaction commit) succeeds, so a failure inside the seeder itself will still be retried.

…ators

Agent-Logs-Url: https://github.com/dotnet/efcore/sessions/b8d55ff4-793c-42c8-83b9-9b5536e7bece

Co-authored-by: AndriySvyryd <6539701+AndriySvyryd@users.noreply.github.com>
@AndriySvyryd
Copy link
Copy Markdown
Member

@copilot Also apply this logic in Migrate(Async)Implementation

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 14, 2026

@copilot Also apply this logic in Migrate(Async)Implementation

Done in 4cdf8d2. Removed the ChangeTracker.Clear() branch from both MigrateImplementation and MigrateImplementationAsync, and renamed MigrationExecutionState.SeedingAttempted to SeedingCompleted (set only after a successful seed) so the seeder is skipped on retry once it has completed.

Copilot AI changed the title Don't clear ChangeTracker on EnsureCreated retry; skip seeder if it already ran Don't clear ChangeTracker on EnsureCreated/Migrate retry; skip seeder if it already ran May 14, 2026
Copilot AI requested a review from AndriySvyryd May 14, 2026 19:08
@AndriySvyryd AndriySvyryd requested a review from Copilot May 14, 2026 19:21
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Follow-up to #38211 that walks back the ChangeTracker.Clear() calls introduced into EnsureCreated[Async] and Migrate[Async] retry paths (which were too invasive on user-tracked state) and instead prevents double-seeding by tracking whether the seeder has already completed.

Changes:

  • Replace the per-retry ChangeTracker.Clear() branches in RelationalDatabaseCreator and CosmosDatabaseCreator with a Seeded StrongBox flag that short-circuits the seeder on retries.
  • In Migrator, gate seeder invocation on !state.SeedingCompleted and set the flag after the seeder runs; rename MigrationExecutionState.SeedingAttemptedSeedingCompleted and update the public API baseline.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/EFCore.Relational/Storage/RelationalDatabaseCreator.cs Replaces Retrying/ChangeTracker.Clear() with a Seeded flag short-circuit in sync/async EnsureCreated.
src/EFCore.Relational/Migrations/MigrationExecutionState.cs Renames SeedingAttempted to SeedingCompleted and updates the XML doc.
src/EFCore.Relational/Migrations/Internal/Migrator.cs Gates sync/async seeder execution on !SeedingCompleted and sets the flag after seeding.
src/EFCore.Relational/EFCore.Relational.baseline.json Updates API baseline for the property rename.
src/EFCore.Cosmos/Storage/Internal/CosmosDatabaseCreator.cs Removes retry-clear logic and adds Seeded flag guarding SeedDataAsync.
Comments suppressed due to low confidence (1)

src/EFCore.Relational/Migrations/Internal/Migrator.cs:339

  • Same issue as in MigrateImplementation: state.SeedingCompleted = true is set before the transaction commit on line 348. If the async commit fails transiently, the retry will skip the seeder despite the seeded rows having been rolled back. The flag should be set after CommitAsync succeeds, consistent with the PR description.
                if (!state.SeedingCompleted)
                {
                    await seedAsync(context, state.AnyOperationPerformed, cancellationToken).ConfigureAwait(false);
                    state.SeedingCompleted = true;
                }

Comment thread src/EFCore.Relational/Migrations/Internal/Migrator.cs
@AndriySvyryd AndriySvyryd marked this pull request as ready for review May 14, 2026 19:56
@AndriySvyryd AndriySvyryd requested a review from a team as a code owner May 14, 2026 19:56
@AndriySvyryd AndriySvyryd assigned roji and unassigned AndriySvyryd and Copilot May 14, 2026
@AndriySvyryd AndriySvyryd enabled auto-merge (squash) May 14, 2026 20:02
@roji roji assigned AndriySvyryd and unassigned roji May 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants