Time to live
[TimeToLive] declares that an entity's data expires. Three stores have native expiry, with
genuinely different semantics — the engine maps the declaration to each native mechanism and keeps
the differences documented instead of papering over them.
[Entity("sessions")]
[TimeToLive(3600)] // seconds
public sealed class Session : IEntity<string>, IEntityTimeMark
{
public string Id { get; set; } = "";
public DateTime CreatedAt { get; set; } // MongoDB's expiry counts from this
public string Payload { get; set; } = "";
public string GetKey() => Id;
public void SetKey(string key) => Id = key;
}
What each store does with it
| Store | Mechanism | Expiry counts from | Materialized by |
|---|---|---|---|
| Cosmos DB | container DefaultTimeToLive |
the item's last write | EnsureCollection() |
| Cassandra | table default_time_to_live |
the row's last write | EnsureCollection() |
| MongoDB | a TTL index (expireAfterSeconds) |
the date member's value, per document | EnsureCollection() |
| Relational | — no native TTL; the annotation is ignored (schedule deletes yourself) |
The MongoDB nuance is the important one: Mongo expires per document, relative to a date field.
The engine resolves that date member as the lifecycle CreatedAt (IEntityTimeMark) by
convention, or an explicit member through the fluent model:
model.Entity<Session>(entity => entity
.TimeToLive(x => x.LastSeenAt, TimeSpan.FromHours(1))); // sliding expiry: refresh LastSeenAt on writes
[TimeToLive] on a MongoDB entity with no date member throws at model build with exactly that
guidance — the store has the concept, so an incomplete declaration is an error, not a shrug.
Per-write TTL (Cassandra)
Cassandra can also expire individual writes, overriding the table default:
await uow.CommitAsync(o => o.WithTtl(TimeSpan.FromMinutes(5))); // this flush's inserts expire in 5m
Checking what you declared
Explain() reports the TTL on every model, in the store's own terms — container-level, table
default_time_to_live, or documents expire 3600s after CreatedAt (per-document TTL index) — so
the semantic difference is always one read away. See Explain.