Getting Started
Requirements
MemDb targets .NET 9 or later and ships as a single assembly with no external runtime dependencies.
Installation
dotnet add package HatTrick.MemDbThe package is HatTrick.MemDb; the namespace is HatTrick.Data:
using HatTrick.Data;Configuration
MemDb requires a dataset name. Providing a directory path enables file-backed persistence; omitting the path runs the dataset purely in RAM (see Modes).
MemDb.ConfigureFor<Person>("people", @"C:\data\people")
.Register();ConfigureFor returns a fluent builder; call .Register() when complete. Configure once at startup (or DI registration), before any MemDb.Open call. Configuration is not persisted — serializer, encryption key, indexes, and other settings must be re-supplied on every application start.
Inspecting and removing configuration
Two static helpers manage the in-process configuration registry:
// Test whether a dataset name has been registered (case-insensitive).
bool registered = MemDb.ContainsConfigurationFor("people");
// Remove a previously registered configuration. The dataset must not be open.
MemDb.RemoveConfigurationFor("people");RemoveConfigurationFor throws ArgumentException if the name is not registered and InvalidOperationException if a MemDb<T> instance for the dataset is open. ContainsConfigurationFor guards against duplicate registration in DI setups that may run more than once.
A complete first program
using System;
using HatTrick.Data;
public class Person
{
public long Id { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
}
class Program
{
static void Main()
{
// Configure — once at startup, before any Open calls.
MemDb.ConfigureFor<Person>("people", @"C:\data\people")
.Register();
// Open — dispose flushes pending writes and releases file handles.
using (var db = MemDb.Open<Person>("people"))
{
var person = new Person
{
FirstName = "Eric",
LastName = "Cartman",
BirthDate = new DateTime(2014, 5, 13)
};
// Insert — id auto-assigned and captured via callback.
db.Insert(person, id => person.Id = id);
// Update — by id.
db.Update(p => p.MiddleName = "Theodore", person.Id);
// Find — returns a deep clone, never a cache reference.
var found = db.Find(person.Id);
Console.WriteLine($"{found.FirstName} {found.MiddleName} {found.LastName}");
}
}
}Expected output:
Eric Theodore CartmanNext steps
- Core Concepts — operational modes, persistence model, flush semantics, and concurrency guarantees
- Architecture — how the engine is wired internally and how data moves between cache and disk
- Basic Operations — the full read/write API
- Queries — the fluent query builder for filtering, sorting, aggregation, and query-scoped writes