Generic Keys
MapCrud supports four primary key types out of the box: Guid, int, long, and string.
The key type is auto-discovered from the entity using a priority-based convention system.
Key Discovery Priority
For a given entity type, MapCrud checks in this order:
[Key]attribute (fromSystem.ComponentModel.DataAnnotations)- Property named
Id - Property named
{ClassName}Id(e.g.,ProductIdfor classProduct) - Fallback:
Guidwith no property
Supported Key Types and Route Constraints
| Key Type | Route Constraint | Example Route |
|---|---|---|
Guid |
{id:guid} |
/products/{id:guid} |
int |
{id:int} |
/products/{id:int} |
long |
{id:long} |
/products/{id:long} |
string |
{id} (none) |
/products/{id} |
An invalid ID format (e.g., a non-integer for an int key) returns 400 Bad Request with a descriptive message.
Explicit Key Override
Override the auto-discovered key type when convention is insufficient:
app.MapCrud<Product>("products", o => o.WithKey<int>());
Guid v7 Auto-Generation
For entities with a Guid primary key, MapCrud automatically generates a sortable UUID v7
when the key is Guid.Empty or not set on a POST request:
.NET 9+: usesGuid.CreateVersion7()for true time-ordered v7 UUIDs.NET 8: falls back toGuid.NewGuid()(random v4)
Client-provided GUIDs are preserved as-is.
IRepository with Generic Key
The repository interface is generic over both entity and key type:
public interface IRepository<T, TKey> where T : class
{
Task<T?> GetByIdAsync(TKey id, string? include = null, bool includeDeleted = false);
Task<T?> UpdateAsync(TKey id, T entity);
Task<bool> DeleteAsync(TKey id);
// ...
}
IRepository<T> is a convenience alias that defaults TKey to Guid.
Related Features
- Getting Started — Basic entity registration
- DTO Mapping — Using DTOs with generic key entities