Skip to main content

Relations & Indexes

intermediate14 min readLesson 104 of 180

Primary keys, foreign keys, and secondary indexes as derived structures every write must maintain.

Modeling relations without a database

SQL thinking transfers directly to repository design:

  • Primary key โ†’ the map key (id), unique and immutable
  • Foreign key โ†’ a field referencing another aggregate's id (Expense.categoryId())
  • JOIN โ†’ a method that combines repositories or a denormalized view
  • UNIQUE constraint โ†’ the store checks and rejects duplicates (save throws on conflicting email)
  • INDEX โ†’ a secondary Map<String, List<Expense>> byCategory, kept consistent on every write

That last one is the deep idea: an index is a derived structure. Every write path must maintain it โ€” the classic bug is updating the main store and forgetting the index:

public Expense save(Expense e) {
    Expense old = store.put(e.id(), e);
    if (old != null) byCategory.get(old.category()).remove(old);
    byCategory.computeIfAbsent(e.category(), k -> new ArrayList<>()).add(e);
    return e;
}

Rebuilding indexes on read (findAll filters on the fly) is correct but O(n) per query โ€” the tradeoff databases charge you for.

Now practice

Persistence LabA full in-memory repository, the safe-vs-injected query contrast, and honest index maintenance.3 challenges ยท ยท ~40 min