Table of Contents

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:

  1. [Key] attribute (from System.ComponentModel.DataAnnotations)
  2. Property named Id
  3. Property named {ClassName}Id (e.g., ProductId for class Product)
  4. Fallback: Guid with 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+: uses Guid.CreateVersion7() for true time-ordered v7 UUIDs
  • .NET 8: falls back to Guid.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.