Repository navigation
Triggers and Views
Tom Laird-McConnell edited this page May 24, 2026
·
3 revisions
Triggers run inline after each save or delete. They receive the object, the trigger kind (Saved or Deleted), and the full DB instance.
var db = await catalog.GetDatabaseAsync("mydb", config =>
{
config.Store<Note>();
config.On<Note>(async (note, kind, db) =>
{
Console.WriteLine($"Note {note.NoteId} was {kind}");
});
});Use On triggers to build derived objects that stay in sync automatically. Whenever the trigger runs you can create/update/delete other objects.
public class NoteView
{
[Key]
public string Id { get; set; } = "";
[Queryable(QueryableMode.NotAnalyzed)]
public string NoteId { get; set; } = "";
[Queryable]
public string AuthorDisplay { get; set; } = "";
[Queryable]
public string Content { get; set; } = "";
}
var db = await catalog.GetDatabaseAsync("mydb", config =>
{
config.Store<Note>();
config.Store<NoteView>();
config.On<Note>(async (note, kind, db) =>
{
if (kind == TriggerKind.Deleted)
{
await db.DeleteManyAsync<NoteView>(nv => nv.NoteId == note.NoteId);
return;
}
var actor = await db.GetAsync<Actor>(note.AuthorId);
await db.SaveAsync(new NoteView
{
Id = $"nv-{note.NoteId}",
NoteId = note.NoteId,
AuthorDisplay = actor?.DisplayName ?? "",
Content = note.Content,
});
});
});Handlers can trigger further handlers (cascading views). Cycle detection prevents infinite loops -- if the same type appears twice in a handler chain, processing stops.
LottaDB registers built-in On handlers for:
- Lucene indexing -- every save/delete updates the Lucene index automatically
-
JsonSchema-- when a JsonSchema entity is saved, the dynamic mapper is updated and documents are re-indexed if the schema changed. When deleted, the mapper and Lucene entries are removed.
Handler errors never block the source save/delete. They are captured in ObjectResult.Errors:
var result = await db.SaveAsync(note);
if (result.Errors.Count > 0)
{
// log handler failures
}