Summary
Add DynamoDB EnsureCreated / schema creation support following EF Core Cosmos and relational provider patterns.
Current provider can translate/write items, but DynamoDB Local/test containers require physical tables to exist before seed/save writes can run. This blocks specification tests and any TestStore.InitializeAsync flow that assumes provider EnsureCreated can provision backing store resources.
Desired provider behavior
Follow Cosmos/relational pattern:
SaveChanges must not auto-create tables.
- Calling
DbContext.Database.EnsureCreated() / EnsureCreatedAsync() is explicit opt-in to create missing backing resources.
- If caller does not call
EnsureCreated, tables are expected to be provisioned externally.
- MVP can be model-driven with provider defaults; no per-call options required initially.
Relational precedent:
EnsureCreated() creates database/tables from model.
- Opt-out is: do not call
EnsureCreated; use migrations/external schema management.
Cosmos precedent:
EnsureCreatedAsync() creates database and containers via CreateDatabaseIfNotExistsAsync / CreateContainerIfNotExistsAsync.
- Container definitions are derived from EF model annotations: container name, partition key, TTL, throughput, indexes, etc.
- No per-call options struct; behavior is model-driven.
Mongo precedent for later consideration:
- Mongo adds provider-specific
MongoDatabaseCreationOptions to control missing collections/indexes.
- We can defer analogous Dynamo options until needed.
Scope
Implement DynamoDB database/table creation support sufficient for local/test-container and normal EnsureCreated usage.
Required
- Register DynamoDB database creator service:
IDatabaseCreator implementation, e.g. DynamoDatabaseCreator.
- Support sync and async EF APIs where practical:
EnsureCreated() / EnsureCreatedAsync()
EnsureDeleted() / EnsureDeletedAsync()
CanConnect() / CanConnectAsync() if feasible.
- Derive physical table definitions from existing provider metadata.
- Create missing DynamoDB tables before model seed/save writes run.
- Wait for table active after creation.
- Delete mapped tables for
EnsureDeleted.
- Integrate with EF model seed/
UseSeeding paths if applicable, matching Cosmos behavior.
Table creation
For each table group:
- Table name from centralized table-group metadata:
src/EntityFrameworkCore.DynamoDb/Extensions/DynamoModelExtensions.cs
GetTableGroupName() / ComputeTableGroupName()
- Key source from inheritance-aware key metadata:
ResolveKeyMappedEntityType()
- Base table key:
- partition key property -> DynamoDB HASH key
- optional sort key property -> DynamoDB RANGE key
- Attribute names from
GetAttributeName().
- Attribute scalar types from effective provider CLR/key type logic:
- string ->
ScalarAttributeType.S
- numeric ->
ScalarAttributeType.N
- byte[] ->
ScalarAttributeType.B
Index creation
Create configured secondary indexes from existing metadata:
- Runtime index model:
src/EntityFrameworkCore.DynamoDb/Metadata/Internal/DynamoRuntimeTableModel.cs
DynamoRuntimeTableModel
DynamoTableDescriptor
DynamoIndexDescriptor
- Runtime initializer that already builds index descriptors:
src/EntityFrameworkCore.DynamoDb/Infrastructure/Internal/DynamoModelRuntimeInitializer.cs
BuildRuntimeTableModel
BuildSourceDescriptors
BuildGlobalSecondaryIndexDescriptor
BuildLocalSecondaryIndexDescriptor
- Index annotations/extensions:
src/EntityFrameworkCore.DynamoDb/Extensions/DynamoIndexExtensions.cs
DynamoSecondaryIndexKind.Global
DynamoSecondaryIndexKind.Local
DynamoSecondaryIndexProjectionType
Need map descriptors to AWS SDK table create inputs:
GlobalSecondaryIndexes
LocalSecondaryIndexes
KeySchema
AttributeDefinitions
- projection type
Deduplicate AttributeDefinitions across table and indexes.
Billing/defaults
MVP default:
- Use
BillingMode.PAY_PER_REQUEST so no throughput config is required and DynamoDB Local/test containers work out of box.
Later enhancement:
- Add provider model annotations/options for billing mode and provisioned throughput if needed.
- Possible provider-specific API similar to Mongo:
DynamoDatabaseCreationOptions(CreateMissingTables, CreateSecondaryIndexes, BillingMode, ...)
Important current code references
Provider registration likely belongs near:
src/EntityFrameworkCore.DynamoDb/Extensions/DynamoServiceCollectionExtensions.cs (or equivalent service registration file)
Write paths currently assume tables exist:
src/EntityFrameworkCore.DynamoDb/Storage/DynamoSaveChangesPlanner.cs
src/EntityFrameworkCore.DynamoDb/Storage/DynamoPartiqlStatementFactory.cs
src/EntityFrameworkCore.DynamoDb/Storage/DynamoWriteExecutor.cs
src/EntityFrameworkCore.DynamoDb/Storage/DynamoClientWrapper.cs
Runtime table/index metadata already exists and should be reused:
src/EntityFrameworkCore.DynamoDb/Metadata/Internal/DynamoRuntimeTableModel.cs
src/EntityFrameworkCore.DynamoDb/Infrastructure/Internal/DynamoModelRuntimeInitializer.cs
Table/key helpers recently centralized:
src/EntityFrameworkCore.DynamoDb/Extensions/DynamoModelExtensions.cs
GetTableGroupName()
ComputeTableGroupName()
ResolveTableMappedEntityType()
ResolveKeyMappedEntityType()
Test infra currently only ensures client exists, not tables:
tests/EntityFrameworkCore.DynamoDb.SpecificationTests/TestUtilities/DynamoTestStore.cs
Acceptance criteria
context.Database.EnsureCreated() creates all required DynamoDB tables for mapped root/table groups.
context.Database.EnsureCreatedAsync() async equivalent works.
- DynamoDB Local/test container seed writes no longer fail due to missing table.
- Tables use correct PK/SK attribute names and DynamoDB scalar types.
- Configured GSIs and LSIs are created.
- Shared-table/entity inheritance mappings create one physical table per table group.
- Calling
EnsureCreated repeatedly is idempotent.
EnsureDeleted removes mapped tables and ignores missing tables.
- Unit/integration tests cover:
- PK-only table
- PK+SK table
- TPH/shared table inheritance
- GSI
- LSI
- repeated
EnsureCreated
- seed data after creation
Notes
This work should land before continuing current spec-test branch work, because tests using DynamoDB Local need actual table definitions. Provider should not add table creation to SaveChanges; explicit EnsureCreated is EF-compatible opt-in.
Summary
Add DynamoDB
EnsureCreated/ schema creation support following EF Core Cosmos and relational provider patterns.Current provider can translate/write items, but DynamoDB Local/test containers require physical tables to exist before seed/save writes can run. This blocks specification tests and any
TestStore.InitializeAsyncflow that assumes providerEnsureCreatedcan provision backing store resources.Desired provider behavior
Follow Cosmos/relational pattern:
SaveChangesmust not auto-create tables.DbContext.Database.EnsureCreated()/EnsureCreatedAsync()is explicit opt-in to create missing backing resources.EnsureCreated, tables are expected to be provisioned externally.Relational precedent:
EnsureCreated()creates database/tables from model.EnsureCreated; use migrations/external schema management.Cosmos precedent:
EnsureCreatedAsync()creates database and containers viaCreateDatabaseIfNotExistsAsync/CreateContainerIfNotExistsAsync.Mongo precedent for later consideration:
MongoDatabaseCreationOptionsto control missing collections/indexes.Scope
Implement DynamoDB database/table creation support sufficient for local/test-container and normal
EnsureCreatedusage.Required
IDatabaseCreatorimplementation, e.g.DynamoDatabaseCreator.EnsureCreated()/EnsureCreatedAsync()EnsureDeleted()/EnsureDeletedAsync()CanConnect()/CanConnectAsync()if feasible.EnsureDeleted.UseSeedingpaths if applicable, matching Cosmos behavior.Table creation
For each table group:
src/EntityFrameworkCore.DynamoDb/Extensions/DynamoModelExtensions.csGetTableGroupName()/ComputeTableGroupName()ResolveKeyMappedEntityType()GetAttributeName().ScalarAttributeType.SScalarAttributeType.NScalarAttributeType.BIndex creation
Create configured secondary indexes from existing metadata:
src/EntityFrameworkCore.DynamoDb/Metadata/Internal/DynamoRuntimeTableModel.csDynamoRuntimeTableModelDynamoTableDescriptorDynamoIndexDescriptorsrc/EntityFrameworkCore.DynamoDb/Infrastructure/Internal/DynamoModelRuntimeInitializer.csBuildRuntimeTableModelBuildSourceDescriptorsBuildGlobalSecondaryIndexDescriptorBuildLocalSecondaryIndexDescriptorsrc/EntityFrameworkCore.DynamoDb/Extensions/DynamoIndexExtensions.csDynamoSecondaryIndexKind.GlobalDynamoSecondaryIndexKind.LocalDynamoSecondaryIndexProjectionTypeNeed map descriptors to AWS SDK table create inputs:
GlobalSecondaryIndexesLocalSecondaryIndexesKeySchemaAttributeDefinitionsDeduplicate
AttributeDefinitionsacross table and indexes.Billing/defaults
MVP default:
BillingMode.PAY_PER_REQUESTso no throughput config is required and DynamoDB Local/test containers work out of box.Later enhancement:
DynamoDatabaseCreationOptions(CreateMissingTables, CreateSecondaryIndexes, BillingMode, ...)Important current code references
Provider registration likely belongs near:
src/EntityFrameworkCore.DynamoDb/Extensions/DynamoServiceCollectionExtensions.cs(or equivalent service registration file)Write paths currently assume tables exist:
src/EntityFrameworkCore.DynamoDb/Storage/DynamoSaveChangesPlanner.cssrc/EntityFrameworkCore.DynamoDb/Storage/DynamoPartiqlStatementFactory.cssrc/EntityFrameworkCore.DynamoDb/Storage/DynamoWriteExecutor.cssrc/EntityFrameworkCore.DynamoDb/Storage/DynamoClientWrapper.csRuntime table/index metadata already exists and should be reused:
src/EntityFrameworkCore.DynamoDb/Metadata/Internal/DynamoRuntimeTableModel.cssrc/EntityFrameworkCore.DynamoDb/Infrastructure/Internal/DynamoModelRuntimeInitializer.csTable/key helpers recently centralized:
src/EntityFrameworkCore.DynamoDb/Extensions/DynamoModelExtensions.csGetTableGroupName()ComputeTableGroupName()ResolveTableMappedEntityType()ResolveKeyMappedEntityType()Test infra currently only ensures client exists, not tables:
tests/EntityFrameworkCore.DynamoDb.SpecificationTests/TestUtilities/DynamoTestStore.csAcceptance criteria
context.Database.EnsureCreated()creates all required DynamoDB tables for mapped root/table groups.context.Database.EnsureCreatedAsync()async equivalent works.EnsureCreatedrepeatedly is idempotent.EnsureDeletedremoves mapped tables and ignores missing tables.EnsureCreatedNotes
This work should land before continuing current spec-test branch work, because tests using DynamoDB Local need actual table definitions. Provider should not add table creation to
SaveChanges; explicitEnsureCreatedis EF-compatible opt-in.