Type to search pages and rules.

Browse pages

EF Core Persistence

This extension states the Entity Framework Core form of the read, query and mapping rules.

Markdown38 provisions

Intent#

This extension states the Entity Framework Core form of the read, query and mapping rules. It applies to aggregates with accepted relational navigation, change-tracking, or provider requirements that the baseline provider cannot satisfy.

Activation#

Activation scope: local.

Applicable specification kinds: module, use-case.

The consumer enables efcore only after a decision records aggregate scope, relational requirement, data evolution effect, and the Marten baseline gap.

Baseline relationship#

For Entity Framework Core-owned aggregate paths, this extension replaces:

  • litespec/backend/dotnet/persistence#query-through-iquerysession: EF Core queries use IApplicationDbContext.
  • litespec/backend/persistence#keep-mappings-and-aliases-explicit: EF Core mappings use IEntityTypeConfiguration<T> classes.
  • litespec/backend/dotnet/packages#keep-application-dependencies-narrow: Application references the Entity Framework Core query surface its query interface needs.
  • litespec/backend/architecture#separate-command-and-query-behavior: it replaces only the read half, and the invariant half still binds.

For an EF Core-owned command with durable delivery, this extension also replaces:

  • litespec/ext/outbox#stage-messages-with-business-work
  • litespec/ext/outbox#reject-independent-outbox-commits

Every other baseline provision binds EF Core-owned paths unchanged.

This extension switches on no optional record type.

Standards#

Record EF Core replacement scope#

ruleguidance
litespec/backend/dotnet/ext/efcore#record-ef-core-replacement-scope
Requirement

An EF Core adoption decision MUST name affected aggregates, data evolution, transaction requirements, query impact, package changes, and rollback plan.

Why

The decision describes the complete persistence replacement for its selected aggregates.

Checka reviewer answers

Does the decision name aggregates, evolution, transactions, queries, packages, and rollback?

Marked guidance: a reviewer answers this question.

Retain unaffected baseline persistence#

ruleguidance
litespec/backend/dotnet/ext/efcore#retain-unaffected-baseline-persistence
Requirement

An unaffected aggregate MUST retain baseline persistence rules.

Why

Local EF Core adoption does not change ownership of other aggregate paths.

Checka reviewer answers

Does every unaffected aggregate path retain its baseline persistence behavior?

Marked guidance: a reviewer answers this question.

Use one write provider#

rulecheckable
litespec/backend/dotnet/ext/efcore#use-one-write-provider
Requirement

An EF Core-owned Command MUST stage aggregate writes through exactly one selected write provider.

Why

One provider gives the Command one atomic commit boundary.

Checkchecked by a tool

EfCoreTransactionTests stage aggregate work through one selected provider.

Marked checkable: the tool named here checks it.

Reject mixed provider writes#

rulecheckable
litespec/backend/dotnet/ext/efcore#reject-mixed-provider-writes
Requirement

A Command MUST NOT stage aggregate writes through both Marten-backed and EF Core-backed repositories.

Why

Independent provider commits cannot preserve one local aggregate invariant.

Checkchecked by a tool

EfCoreTransactionTests assert no mixed Marten and EF Core aggregate repository writes.

Marked checkable: the tool named here checks it.

Record provider selection#

ruleguidance
litespec/backend/dotnet/ext/efcore#record-provider-selection
Requirement

An EF Core adoption decision MUST name Command provider selection and its architecture-test evidence.

Why

The decision makes provider ownership reviewable for each selected Command path.

Checka reviewer answers

Does the decision name each Command path's provider and its test evidence?

Marked guidance: a reviewer answers this question.

Register one Command post-handler#

rulecheckable
litespec/backend/dotnet/ext/efcore#register-one-command-post-handler
Requirement

An EF Core-owned Command MUST register only its selected provider's LiteBus post-handler.

Why

A Marten post-handler cannot commit EF Core-owned work.

Checkchecked by a tool

EfCoreTransactionTests assert each command resolves only its selected provider post-handler.

Marked checkable: the tool named here checks it.

Resolve cross-provider invariants#

ruleguidance
litespec/backend/dotnet/ext/efcore#resolve-cross-provider-invariants
Requirement

An accepted atomic cross-provider invariant MUST move its aggregates to one provider or use a reviewed shared transaction mechanism.

Why

One local invariant requires one verified atomic persistence boundary.

Checka reviewer answers

Does each cross-provider invariant use one provider or a reviewed shared transaction?

Marked guidance: a reviewer answers this question.

Stage aggregate writes in repositories#

rulecheckable
litespec/backend/dotnet/ext/efcore#stage-aggregate-writes-in-repositories
Requirement

An EF Core Infrastructure repository MUST use its scoped DbContext to stage aggregate changes.

Why

Repository staging keeps write persistence outside Application handlers.

Checkchecked by a tool

EfCoreWriteTests stage changes through the scoped DbContext.

Marked checkable: the tool named here checks it.

Exclude direct handler commits#

rulecheckable
litespec/backend/dotnet/ext/efcore#exclude-direct-handler-commits
Requirement

An EF Core Command handler MUST NOT inject DbContext or call SaveChangesAsync.

Why

The selected post-handler owns the one Command commit.

Checkchecked by a tool

EfCoreWriteTests assert handlers inject no DbContext and call no SaveChangesAsync.

Marked checkable: the tool named here checks it.

Define EF Core query roots#

rulecheckable
litespec/backend/dotnet/ext/efcore#define-ef-core-query-roots
Requirement

Application MUST own one public IApplicationDbContext exposing required generic sets or named query roots, referencing only the Entity Framework Core abstractions that interface needs.

Why

The interface defines the EF Core query boundary without exposing the Infrastructure DbContext. The permitted surface is the query types the interface exposes and the manifest-pinned Microsoft.EntityFrameworkCore package that declares them.

Checkchecked by a tool

EfCoreReadTests assert one owned IApplicationDbContext and no wider EF surface.

Marked checkable: the tool named here checks it.

Implement query roots in Infrastructure#

rulecheckable
litespec/backend/dotnet/ext/efcore#implement-query-roots-in-infrastructure
Requirement

Infrastructure MUST implement IApplicationDbContext with the application DbContext.

Why

The provider implementation remains behind Application's query interface.

Checkchecked by a tool

EfCoreReadTests assert the Infrastructure DbContext implements the owned query interface.

Marked checkable: the tool named here checks it.

Retain Marten query boundary#

rulecheckable
litespec/backend/dotnet/ext/efcore#retain-marten-query-boundary
Requirement

A Marten-owned query path MUST retain the baseline IQuerySession boundary.

Why

EF Core adoption does not alter read ownership for Marten-backed aggregates.

Checkchecked by a tool

EfCoreReadTests assert Marten query handlers retain IQuerySession.

Marked checkable: the tool named here checks it.

Project EF Core queries directly#

rulecheckable
litespec/backend/dotnet/ext/efcore#project-ef-core-queries-directly
Requirement

An EF Core query handler MUST use AsNoTracking, filter before materialization, order and limit deterministically, and project records.

Why

Handlers return shaped results without loading mutable aggregate state. No command enforces an invariant from a read projection.

Checkchecked by a tool

EfCoreReadTests assert no tracking, authorized filters, deterministic limits, projections, and no invariant from a projection.

Marked checkable: the tool named here checks it.

Avoid per-aggregate read stores#

rulecheckable
litespec/backend/dotnet/ext/efcore#avoid-per-aggregate-read-stores
Requirement

An EF Core query implementation MUST NOT add one read-store interface per aggregate.

Why

IApplicationDbContext supplies the selected EF Core query boundary.

Checkchecked by a tool

EfCoreReadTests assert no per-aggregate read-store interface pattern exists.

Marked checkable: the tool named here checks it.

Resolve the tenant at context creation#

rulecheckable
litespec/backend/dotnet/ext/efcore#resolve-the-tenant-at-context-creation
Requirement

An EF Core DbContext MUST resolve the tenant when the context is created and apply the tenant filter to tenant-owned sets.

Why

Resolution at creation keeps the tenant out of every query, and the filter convention applies it to each tenant-owned set.

Checkchecked by a tool

EfCoreReadTests assert tenant resolution at creation and tenant filters on owned sets.

Marked checkable: the tool named here checks it.

Commit EF Core Command work once#

rulecheckable
litespec/backend/dotnet/ext/efcore#commit-ef-core-command-work-once
Requirement

An EF Core LiteBus post-handler MUST call SaveChangesAsync once for its owned Command.

Why

One post-handler commit preserves the Command's provider transaction boundary.

Checkchecked by a tool

EfCoreCommitTests observe one post-handler SaveChangesAsync call per owned Command.

Marked checkable: the tool named here checks it.

Process changed aggregate events#

rulecheckable
litespec/backend/dotnet/ext/efcore#process-changed-aggregate-events
Requirement

An EF Core post-handler MUST collect Domain events from changed aggregates and follow their documented delivery classification.

Why

Event delivery follows the same aggregate changes that the handler commits.

Checkchecked by a tool

EfCoreCommitTests classify and stage Domain events correctly.

Marked checkable: the tool named here checks it.

Use durable outbox delivery#

rulecheckable
litespec/backend/dotnet/ext/efcore#use-durable-outbox-delivery
Requirement

An EF Core Command requiring durable delivery MUST use the outbox extension without committing a Marten session.

Why

EF Core-owned durable work remains in the selected provider transaction.

Checkchecked by a tool

EfCoreCommitTests assert EF Core durable Commands commit no Marten session.

Marked checkable: the tool named here checks it.

Stage EF Core outbox records together#

rulecheckable
litespec/backend/dotnet/ext/efcore#stage-ef-core-outbox-records-together
Requirement

An EF Core-owned Command MUST map and stage outbox records with aggregate changes through the same DbContext.

Why

The DbContext transaction makes the outbox record and business work durable together.

Checkchecked by a tool

EfCoreOutboxTests stage message and business work through one DbContext.

Marked checkable: the tool named here checks it.

Reject cross-provider outbox storage#

rulecheckable
litespec/backend/dotnet/ext/efcore#reject-cross-provider-outbox-storage
Requirement

An EF Core-owned Command MUST NOT store its required outbox record through a Marten session.

Why

A Marten outbox transaction cannot atomically commit an EF Core aggregate change.

Checkchecked by a tool

EfCoreOutboxTests assert EF Core Commands write no outbox record through Marten.

Marked checkable: the tool named here checks it.

Configure EF Core mappings in Infrastructure#

rulecheckable
litespec/backend/dotnet/ext/efcore#configure-ef-core-mappings-in-infrastructure
Requirement

Infrastructure MUST own IEntityTypeConfiguration<T> classes for EF Core persistence mappings.

Why

Relational mapping behavior belongs to the provider-owning layer.

Checkchecked by a tool

EfCoreMappingTests assert EF Core mappings use Infrastructure-owned configuration classes.

Marked checkable: the tool named here checks it.

Configure relational details explicitly#

ruleguidance
litespec/backend/dotnet/ext/efcore#configure-relational-details-explicitly
Requirement

An EF Core mapping MUST explicitly configure typed IDs, owned values, fields, indexes, constraints, precision, deletes, concurrency tokens, and database names.

Why

Explicit configuration makes storage contract changes visible in code review and migrations.

Checka reviewer answers

Does the mapping review record every declared relational configuration category?

Marked guidance: a reviewer answers this question.

Retain Domain state values#

rulecheckable
litespec/backend/dotnet/ext/efcore#retain-domain-state-values
Requirement

EF Core persistence MUST retain the Domain aggregate's single {Aggregate}State value.

Why

The aggregate remains the owner of lifecycle state and state-specific business facts.

A relational column holds the active state record and its discriminator, which is the same contract the baseline provider stores in its document. The column never holds an enumerated integer, because that discards the state-specific facts the record carries and reintroduces the shape litespec/backend/domain#model-every-closed-set-of-domain-values-as-a-closed-type-hierarchy removes. A state case with its own fields maps to an owned type or to its own table. The discriminator selects which one a read materializes.

Checkchecked by a tool

EfCoreStateTests retain the aggregate's one Domain state value.

Marked checkable: the tool named here checks it.

Map stable relational state shape#

rulecheckable
litespec/backend/dotnet/ext/efcore#map-stable-relational-state-shape
Requirement

Infrastructure MUST map a stable discriminator and every state-specific value without adding Domain lifecycle flags or duplicate nullable state properties.

Why

Relational storage can use columns while Domain retains its state-record hierarchy.

Checkchecked by a tool

EfCoreStateTests assert no relational lifecycle flags or duplicate nullable state values.

Marked checkable: the tool named here checks it.

Use direct state mapping only when supported#

rulecheckable
litespec/backend/dotnet/ext/efcore#use-direct-state-mapping-only-when-supported
Requirement

An EF Core mapping MAY use direct owned or JSON state mapping only when pinned versions materialize, track, and round-trip each state record.

Why

A direct mapping needs complete provider behavior for every sealed state case.

Checkchecked by a tool

EfCoreStateTests materialize, track, and round-trip every state case.

Marked checkable: the tool named here checks it.

Map unsupported state shapes in Infrastructure#

rulecheckable
litespec/backend/dotnet/ext/efcore#map-unsupported-state-shapes-in-infrastructure
Requirement

An unsupported direct state mapping MUST use an Infrastructure persistence type with discriminator and state-specific columns.

Why

The Infrastructure repository maps the persistence type to and from the Domain hierarchy.

Checkchecked by a tool

EfCoreStateTests map valid discriminator values to Domain states.

Marked checkable: the tool named here checks it.

Review new persisted states#

ruleguidance
litespec/backend/dotnet/ext/efcore#review-new-persisted-states
Requirement

A new persisted state MUST include reviewed migration, mixed-version behavior, rollback behavior, and an integration fixture.

Why

New state values affect stored rows and application versions that read them.

Example

PostRow maps state_type, published_at, and archived_at to one PostState record.

Checka reviewer answers

Does the new state review cover migration, mixed versions, rollback, and a fixture?

Marked guidance: a reviewer answers this question.

Generate migrations for schema changes#

rulecheckable
litespec/backend/dotnet/ext/efcore#generate-migrations-for-schema-changes
Requirement

An EF Core schema change MUST generate a migration.

Why

The migration is the explicit reviewed description of relational schema evolution.

Checkchecked by a tool

EfCoreMigrationsTests assert EF Core schema diffs include a generated migration.

Marked checkable: the tool named here checks it.

Review migration effects#

ruleguidance
litespec/backend/dotnet/ext/efcore#review-migration-effects
Requirement

A migration review MUST cover tables, columns, indexes, constraints, data movement, destructive operations, and rollback compatibility.

Why

Each item can affect deployment safety or data recovery.

Checka reviewer answers

Does the migration review cover every declared storage and rollback effect?

Marked guidance: a reviewer answers this question.

Apply migrations as release work#

rulecheckable
litespec/backend/dotnet/ext/efcore#apply-migrations-as-release-work
Requirement

A release process MUST apply EF Core migrations before application startup.

Why

Release-owned execution controls ordering and evidence for schema work.

Checkchecked by a tool

EfCoreMigrationsTests place migration application before replica startup in the release record.

Marked checkable: the tool named here checks it.

Keep migration files together#

rulecheckable
litespec/backend/dotnet/ext/efcore#keep-migration-files-together
Requirement

An EF Core schema change MUST commit migration, model snapshot, and reviewed SQL together.

Why

The three artifacts show intended migration source and resulting relational change.

Checkchecked by a tool

EfCoreMigrationsTests assert each migration commit holds migration, snapshot, and reviewed SQL.

Marked checkable: the tool named here checks it.

Test migration starting states#

rulecheckable
litespec/backend/dotnet/ext/efcore#test-migration-starting-states
Requirement

An EF Core migration MUST apply successfully from an empty database and previous release database.

Why

Both initial setup and upgrade paths need tested relational evolution.

The previous release database is the schema of the last released artifact, not the schema of the previous commit. The test builds it by applying that artifact's migrations to an empty database, then applies the current ones on top. A test that starts from the current migrations minus one proves that the last migration applies, which is the case least likely to be broken.

Checkchecked by a tool

EfCoreMigrationsTests run from empty and previous-release databases.

Marked checkable: the tool named here checks it.

Reject startup schema mutation#

rulecheckable
litespec/backend/dotnet/ext/efcore#reject-startup-schema-mutation
Requirement

Production and staging startup MUST NOT call EnsureCreated, EnsureDeleted, or Migrate.

Why

Replica startup does not own hosted database schema change.

Checkchecked by a tool

EfCoreMigrationsTests assert startup calls none of the prohibited schema APIs.

Marked checkable: the tool named here checks it.

Configure optimistic tokens#

rulecheckable
litespec/backend/dotnet/ext/efcore#configure-optimistic-tokens
Requirement

An EF Core aggregate using concurrency MUST configure a provider-backed token and carry expected version through its Command.

Why

The token connects a caller's expected aggregate version to EF Core write detection.

Checkchecked by a tool

EfCoreConcurrencyTests carry expected version and use the configured EF Core token.

Marked checkable: the tool named here checks it.

Map EF Core concurrency conflict#

rulecheckable
litespec/backend/dotnet/ext/efcore#map-ef-core-concurrency-conflict
Requirement

An EF Core post-handler MUST translate DbUpdateConcurrencyException into the Application conflict contract.

Why

Application exposes a project-owned conflict rather than an EF Core exception type.

Checkchecked by a tool

EfCoreConcurrencyTests map the provider exception to the Application contract.

Marked checkable: the tool named here checks it.

Reject automatic command retry#

rulecheckable
litespec/backend/dotnet/ext/efcore#reject-automatic-command-retry
Requirement

An EF Core post-handler MUST NOT retry the complete Command automatically after a concurrency exception.

Why

A retry can rerun Domain behavior against state that the caller did not approve.

Checkchecked by a tool

EfCoreConcurrencyTests prove no complete Command automatic retry.

Marked checkable: the tool named here checks it.

Conventions#

Use the EF Core Infrastructure layout#

conventionguidance
litespec/backend/dotnet/ext/efcore#use-the-ef-core-infrastructure-layout
Default

Use Infrastructure/Persistence/EfCore/ for ApplicationDbContext, factory, post-handler, configurations, migrations, and repositories.

ReplacementA consumer records a departure from this default as an Exception record with reason, review date, and removal condition.

Example

Infrastructure/Persistence/EfCore/Configurations/ holds persistence mapping classes.

Checka reviewer answers

Does each EF Core Infrastructure path use the default layout or record an Exception?

Marked guidance: a reviewer answers this question.

Use snake-case relational names#

conventioncheckable
litespec/backend/dotnet/ext/efcore#use-snake-case-relational-names
Default

Use the pinned naming-conventions package and verify generated names in each migration, with casing owned by litespec/backend/persistence#use-database-naming-conventions.

ReplacementA consumer records a departure from this default as an Exception record with reason, review date, and removal condition.

Why

The migration shows the exact names that reach the database.

Checkchecked by a tool

EfCoreTests assert generated migrations contain verified snake-case database names.

Marked checkable: the tool named here checks it.

Dependencies#

  • Microsoft.EntityFrameworkCore
  • Npgsql.EntityFrameworkCore.PostgreSQL
  • EFCore.NamingConventions

Verification#

IDMarkEvidence
litespec/backend/dotnet/ext/efcore#record-ef-core-replacement-scopeguidanceDoes the decision name aggregates, evolution, transactions, queries, packages, and rollback?
litespec/backend/dotnet/ext/efcore#retain-unaffected-baseline-persistenceguidanceDoes every unaffected aggregate path retain its baseline persistence behavior?
litespec/backend/dotnet/ext/efcore#use-one-write-providercheckableEfCoreTransactionTests stage aggregate work through one selected provider.
litespec/backend/dotnet/ext/efcore#reject-mixed-provider-writescheckableEfCoreTransactionTests assert no mixed Marten and EF Core aggregate repository writes.
litespec/backend/dotnet/ext/efcore#record-provider-selectionguidanceDoes the decision name each Command path's provider and its test evidence?
litespec/backend/dotnet/ext/efcore#register-one-command-post-handlercheckableEfCoreTransactionTests assert each command resolves only its selected provider post-handler.
litespec/backend/dotnet/ext/efcore#resolve-cross-provider-invariantsguidanceDoes each cross-provider invariant use one provider or a reviewed shared transaction?
litespec/backend/dotnet/ext/efcore#stage-aggregate-writes-in-repositoriescheckableEfCoreWriteTests stage changes through the scoped DbContext.
litespec/backend/dotnet/ext/efcore#exclude-direct-handler-commitscheckableEfCoreWriteTests assert handlers inject no DbContext and call no SaveChangesAsync.
litespec/backend/dotnet/ext/efcore#define-ef-core-query-rootscheckableEfCoreReadTests assert one owned IApplicationDbContext and no wider EF surface.
litespec/backend/dotnet/ext/efcore#implement-query-roots-in-infrastructurecheckableEfCoreReadTests assert the Infrastructure DbContext implements the owned query interface.
litespec/backend/dotnet/ext/efcore#retain-marten-query-boundarycheckableEfCoreReadTests assert Marten query handlers retain IQuerySession.
litespec/backend/dotnet/ext/efcore#project-ef-core-queries-directlycheckableEfCoreReadTests assert no tracking, authorized filters, deterministic limits, projections, and no invariant from a projection.
litespec/backend/dotnet/ext/efcore#avoid-per-aggregate-read-storescheckableEfCoreReadTests assert no per-aggregate read-store interface pattern exists.
litespec/backend/dotnet/ext/efcore#resolve-the-tenant-at-context-creationcheckableEfCoreReadTests assert tenant resolution at creation and tenant filters on owned sets.
litespec/backend/dotnet/ext/efcore#commit-ef-core-command-work-oncecheckableEfCoreCommitTests observe one post-handler SaveChangesAsync call per owned Command.
litespec/backend/dotnet/ext/efcore#process-changed-aggregate-eventscheckableEfCoreCommitTests classify and stage Domain events correctly.
litespec/backend/dotnet/ext/efcore#use-durable-outbox-deliverycheckableEfCoreCommitTests assert EF Core durable Commands commit no Marten session.
litespec/backend/dotnet/ext/efcore#stage-ef-core-outbox-records-togethercheckableEfCoreOutboxTests stage message and business work through one DbContext.
litespec/backend/dotnet/ext/efcore#reject-cross-provider-outbox-storagecheckableEfCoreOutboxTests assert EF Core Commands write no outbox record through Marten.
litespec/backend/dotnet/ext/efcore#configure-ef-core-mappings-in-infrastructurecheckableEfCoreMappingTests assert EF Core mappings use Infrastructure-owned configuration classes.
litespec/backend/dotnet/ext/efcore#configure-relational-details-explicitlyguidanceDoes the mapping review record every declared relational configuration category?
litespec/backend/dotnet/ext/efcore#retain-domain-state-valuescheckableEfCoreStateTests retain the aggregate's one Domain state value.
litespec/backend/dotnet/ext/efcore#map-stable-relational-state-shapecheckableEfCoreStateTests assert no relational lifecycle flags or duplicate nullable state values.
litespec/backend/dotnet/ext/efcore#use-direct-state-mapping-only-when-supportedcheckableEfCoreStateTests materialize, track, and round-trip every state case.
litespec/backend/dotnet/ext/efcore#map-unsupported-state-shapes-in-infrastructurecheckableEfCoreStateTests map valid discriminator values to Domain states.
litespec/backend/dotnet/ext/efcore#review-new-persisted-statesguidanceDoes the new state review cover migration, mixed versions, rollback, and a fixture?
litespec/backend/dotnet/ext/efcore#generate-migrations-for-schema-changescheckableEfCoreMigrationsTests assert EF Core schema diffs include a generated migration.
litespec/backend/dotnet/ext/efcore#review-migration-effectsguidanceDoes the migration review cover every declared storage and rollback effect?
litespec/backend/dotnet/ext/efcore#apply-migrations-as-release-workcheckableEfCoreMigrationsTests place migration application before replica startup in the release record.
litespec/backend/dotnet/ext/efcore#keep-migration-files-togethercheckableEfCoreMigrationsTests assert each migration commit holds migration, snapshot, and reviewed SQL.
litespec/backend/dotnet/ext/efcore#test-migration-starting-statescheckableEfCoreMigrationsTests run from empty and previous-release databases.
litespec/backend/dotnet/ext/efcore#reject-startup-schema-mutationcheckableEfCoreMigrationsTests assert startup calls none of the prohibited schema APIs.
litespec/backend/dotnet/ext/efcore#configure-optimistic-tokenscheckableEfCoreConcurrencyTests carry expected version and use the configured EF Core token.
litespec/backend/dotnet/ext/efcore#map-ef-core-concurrency-conflictcheckableEfCoreConcurrencyTests map the provider exception to the Application contract.
litespec/backend/dotnet/ext/efcore#reject-automatic-command-retrycheckableEfCoreConcurrencyTests prove no complete Command automatic retry.
litespec/backend/dotnet/ext/efcore#use-the-ef-core-infrastructure-layoutguidanceDoes each EF Core Infrastructure path use the default layout or record an Exception?
litespec/backend/dotnet/ext/efcore#use-snake-case-relational-namescheckableEfCoreTests assert generated migrations contain verified snake-case database names.