room-entity-pattern

star 50

Room entity, DAO, mapper, and migration pattern guide. Use when adding or changing persistence models, join tables, and schema migrations.

AniTrend By AniTrend schedule Updated 6/8/2026

name: room-entity-pattern description: 'Room entity, DAO, mapper, and migration pattern guide. Use when adding or changing persistence models, join tables, and schema migrations.'

Skill: Room Entity / DAO / Mapper / Repository Pattern

Overview

Persistence follows a strict four-file pattern for each domain entity. Reading an existing implementation (e.g., tag) is the fastest way to understand what to produce for a new entity.

Key files to read

  • data/src/main/kotlin/co/anitrend/data/tag/entity/TagEntity.kt — Room @Entity with schema-aware query-builder annotations
  • data/src/main/kotlin/co/anitrend/data/tag/entity/filter/TagQueryFilter.kt — dynamic Room query filter built with the support-query-builder DSL
  • data/src/main/kotlin/co/anitrend/data/tag/ — full package: entity, DAO, mapper, source, repository, usecase, koin

Surrogate-PK rules (join / connection tables)

These rules apply specifically when a table uses a Room-autogenerated surrogate PK (common for many-to-many join tables and local-only caches). They do not apply to entities whose PK is server-provided.

  • Declare the surrogate PK as nullable: @PrimaryKey(autoGenerate = true) val id: Long? = null.
  • Implement IEntity<Long> when the surrogate PK is Long?; implement IEntity<Int> only when the surrogate PK is explicitly Int?.
  • Define a composite unique index over the logical relationship columns: @Index(value = ["tag_id", "media_id"], unique = true).
  • Use @Insert(onConflict = REPLACE) for batch upserts keyed by the composite columns, not the surrogate PK.
  • Never require a non-null surrogate id in interfaces or mapper inputs — Room fills it after insert.

Migration checklist

When making schema-impacting changes:

  1. Bump DATABASE_SCHEMA_VERSION in the Room database class.
  2. Use @AutoMigration(from = X, to = Y) for additive-only changes such as new tables or new columns with safe defaults. Provide a manual Migration object for renames, type changes, constraint changes, or any data transform that @AutoMigration cannot express.
  3. Export and inspect the schema JSON at data/schemas/.../AniTrendStore/<version>.json; verify nullability, indices, and identity hash are as expected.
  4. Build the module to confirm annotation processing and schema export succeed cleanly.
  5. Smoke-test against an older on-device DB (the from version) to confirm migration applies without crashes.
  6. If changing join tables, assert that multiple relationship rows persist and read back correctly (no silent row-collapse due to conflict strategy).
  7. Include a brief schema diff summary in the PR description.

Four-file pattern

File Responsibility
XxxEntity.kt @Entity data class; mirrors DB columns; uses query-builder annotations
XxxDao.kt @Dao interface; @Query, @Insert(onConflict=REPLACE), @Delete
XxxMapper.kt Converts network model → entity; calls DAO upsert in persist()
XxxRepository.kt Implements domain IXxxRepository; wires source + controller into DataState
Install via CLI
npx skills add https://github.com/AniTrend/anitrend-v2 --skill room-entity-pattern
Repository Details
star Stars 50
call_split Forks 5
navigation Branch main
article Path SKILL.md
More from Creator