---
name: feedback_multi_entity_create_self_committing_codegen
description: "Creating N entities that each need a code from a self-committing sequence generator — gen all codes first (entities un-tracked), then atomic final SaveChanges"
metadata: 
  node_type: memory
  type: feedback
  originSessionId: f9f0e3ed-a5c6-40ea-8bec-f67112be9957
---

When a handler must create **N entities in one call** and each needs a unique code from a **self-committing** sequence generator, the naive "create → add → gen-code → next" loop risks the generator's internal `SaveChanges` flushing half-built entities.

**Concrete (S88, create-contract 1→N per winner):** `ContractCodeGenerator.GenerateAsync` runs its OWN `BeginTransactionAsync(Serializable)` + `SaveChanges` + `Commit` per call (to make the `ContractCodeSequence` increment race-safe). That means **every call flushes ALL tracked changes in the shared scoped DbContext**, not just the sequence row.

**Pattern that works:**
1. **Loop 1 — gen all codes:** build each entity as a **LOCAL object** (a `List<T>`), call `GenerateAsync(entity, ...)` to get its code, but do **NOT** `db.X.Add(entity)` yet, and do **NOT** mutate any other tracked entity (e.g. the parent's FK). So the generator's internal `SaveChanges` only ever flushes the sequence row — never a half-built entity.
2. **Loop 2 — add atomically:** `db.X.Add` all N + their changelogs + set the parent link, then **ONE final `SaveChanges`** = atomic. A failure mid-loop-1 wastes only sequence numbers (acceptable — sequences allow gaps), never creates a partial set.

**Why:** the codegen self-commits, so there is NO way to wrap the whole multi-create in one transaction via `IApplicationDbContext` (it has no `BeginTransactionAsync`). Gen-first-then-add is the migration-free atomicity.

**Why:** prevents partial-create on a financial/contract operation; keeps single-entity behavior identical (1 winner → 1 code → 1 add). Single vs multi can diverge on derived values (S88 GiaTri: single = legacy details-sum; ≥2 = per-winner quote total) — branch on `count == 1` to preserve legacy.

**How to apply:** any "create N children from a parent, each needing a generated code/number" — invoices per line, contracts per winner, tickets per asset. Check whether the code generator self-commits (`(DbContext)db` + `BeginTransactionAsync`/`SaveChanges` inside) — if so, gen-before-add. Verify with a reviewer skeptic-ask: "could the mid-loop SaveChanges flush anything unintended?" Idempotency via a single parent→first-child link; re-call guard on that link. Related: [[feedback_cardinality_change_grep_consumers]].
