Skip to content

Entities and Keys

Every root entity type in the DynamoDB EF Core provider must declare a partition key, and optionally a sort key, which together form the item's primary key in DynamoDB.

Defining an Entity

Root entity types (non-owned, non-derived) map to DynamoDB tables and must resolve table keys. Key mapping can use provider APIs (HasPartitionKey(...), HasSortKey(...)), EF key APIs (HasKey(...), [Key], [PrimaryKey]), or conventions. Root entities are independent DynamoDB items; the provider does not support EF Core foreign-key or navigation relationships between them.

modelBuilder.Entity<Order>(b =>
{
    b.ToTable("Orders");
    b.HasPartitionKey(x => x.CustomerId);
    b.HasSortKey(x => x.OrderId); // optional
});

Provider key APIs preferred

`HasPartitionKey(...)` and `HasSortKey(...)` name DynamoDB roles directly and are preferred in docs. EF-native `HasKey(...)` and `[PrimaryKey]` are also supported for one- and two-part table keys; property-level `[Key]` supports a single-property partition key.

If no explicit ToTable(...) is configured, the provider uses the CLR type name as the table name.

No EF relationships

`HasOne(...)`, `HasMany(...)`, `WithOne(...)`, `WithMany(...)`, `HasForeignKey(...)`,
`[ForeignKey]`, and `[InverseProperty]` are not supported. Use complex types for embedded
data, or model separate DynamoDB items/tables as separate root entities and join them in
application code when needed.

Defaults and Overrides

For root entity types, table/key mapping resolves in this order (highest precedence first):

  1. Explicit provider configuration (ToTable(...), HasPartitionKey(...), HasSortKey(...))
  2. EF key configuration (HasKey(...), [Key], [PrimaryKey])
  3. Conventions (PK/PartitionKey, fallback Id/{EntityName}Id, SK/SortKey; table name from CLR type)
  4. Validation outcome (missing partition key throws; partition key resolved with no sort key means partition-key-only)

One EF key property maps to the partition key. Two EF key properties map to partition then sort key. If HasPartitionKey(...) matches the first property of a two-part EF key and no HasSortKey(...) is configured, the second EF key property is still used as the sort key.

Partition Key

Every DynamoDB table has a partition key. Configure it with HasPartitionKey(...) or use conventional property names (PK or PartitionKey, case-insensitive). If neither DynamoDB-specific name exists, Id or EF-discovered {EntityName}Id is used as a fallback partition key name. Id does not create ambiguity when PK or PartitionKey also exists; the DynamoDB-specific name wins.

HasPartitionKey(...) overrides convention-based partition key discovery.

Partition keys must be mapped, non-nullable EF properties and resolve to DynamoDB key-supported provider types (string, number, or binary).

Key Value Generation

DynamoDB does not generate primary key values for you. By convention, string and numeric partition or sort keys are application-assigned: set them before calling SaveChangesAsync.

context.Orders.Add(new Order
{
    CustomerId = "CUST#123",
    OrderId = 42,
    Description = "New order"
});
await context.SaveChangesAsync();

If a numeric key is left unset, EF Core treats the CLR default (for example 0) as the value to write. If a string key is left null, the save fails because DynamoDB key attributes must be present and non-null.

Single-property Guid keys keep EF Core's default client-side generation behavior. Leaving such a Guid key as Guid.Empty lets EF Core assign a new Guid before writing the item.

Composite DynamoDB keys are application-assigned by convention, even when one key part is a Guid. Set both the partition key and sort key before saving, or explicitly configure a client-side value generator for the key part that should be generated.

public sealed class Session
{
    public Guid Id { get; set; }
    public string Name { get; set; } = null!;
}

modelBuilder.Entity<Session>(b =>
{
    b.HasPartitionKey(x => x.Id);
});

Explicit EF Core value-generation configuration still wins over provider conventions when you need a custom client-side generator. DynamoDB still does not generate the value; your EF Core configuration must produce a concrete CLR value before save. For example, use a custom generator for Guid v7 keys:

public sealed class GuidV7ValueGenerator : ValueGenerator<Guid>
{
    public override bool GeneratesTemporaryValues => false;

    public override Guid Next(EntityEntry entry)
        => Guid.CreateVersion7();
}

modelBuilder.Entity<Session>(b =>
{
    b.HasPartitionKey(x => x.Id);
    b.Property(x => x.Id)
        .ValueGeneratedOnAdd()
        .HasValueGenerator<GuidV7ValueGenerator>();
});

A value generator creates the CLR key value. A value converter only changes how that value is stored in DynamoDB.

Sort Key

Sort keys are optional. When present, the table key shape is [partitionKey, sortKey].

Configure with HasSortKey(...) or use conventional property names (SK or SortKey, case-insensitive).

HasSortKey(...) overrides convention-based sort key discovery.

Composite Keys

In DynamoDB, a composite table key means exactly two parts: partition key + sort key.

Composite keys can be configured with provider APIs or EF-native key APIs. With HasKey(...) or [PrimaryKey], property order is DynamoDB-significant: first property is the partition key, second property is the sort key. More than two key properties are invalid.

When provider APIs or conventions configure a sort key, the provider derives the EF primary key as [partitionKey, sortKey] in that order.

Explicit composite-key mapping:

modelBuilder.Entity<Order>(b =>
{
    b.ToTable("Orders");
    b.HasPartitionKey(x => x.CustomerId);
    b.HasSortKey(x => x.OrderId);
});

Convention-based composite-key mapping (no explicit key calls):

public sealed class Order
{
    public string Pk { get; set; } = null!;
    public string Sk { get; set; } = null!;
    public string Description { get; set; } = null!;
}

Common validation failures

- EF key has more than two properties
- EF key and provider key APIs disagree on partition/sort order
- Configuring the same property as both partition key and sort key
- Declaring a sort key without a resolvable partition key
- Ambiguous conventional names (both `PK` and `PartitionKey`, or both `SK` and `SortKey`)

See Table and Key Mapping for full validation rules, key-property requirements, and advanced mapping patterns.

See also