Relationships

August 23, 2026 ยท View on GitHub

Foreign key

@Table
data class Author(
    @PrimaryKey(autoincrement = true) val id: Int = 0,
    val firstName: String,
    val lastName: String,
)

@Table
data class Blog(
    @PrimaryKey(autoincrement = true) val id: Int = 0,
    val name: String,
    @ForeignKey(saveForeignKeyModel = true) val author: Author?,
)

DBFlow stores the author's primary key on Blog and can load Author when you read a Blog.

saveForeignKeyModel = true saves the parent first. Leave it false (default) if you persist the parent yourself.

Enable SQLite enforcement:

@Database(version = 1, foreignKeyConstraintsEnforced = true, tables = [Author::class, Blog::class])

Useful @ForeignKey flags: onDelete / onUpdate (ForeignKeyAction), deferred, references for a non-default column mapping.

Many-to-many

Annotate one side. The plugin generates a join table (Artist_Song here).

@ManyToMany(referencedTable = Song::class)
@Table
data class Artist(
    @PrimaryKey(autoincrement = true) val id: Int = 0,
    val name: String,
)

@Table
data class Song(
    @PrimaryKey(autoincrement = true) val id: Int = 0,
    val name: String,
)

List the generated table if you declare tables explicitly, or look it up:

val row = Artist_Song(id = 0, artist = artist, song = song)
DatabaseObjectLookup.getModelAdapter(Artist_Song::class).save(row)

generateAutoIncrement (default true) adds a Long primary key. Set it false to use both sides' keys as a composite PK.

One-to-many

@OneToMany is a method-level helper for loading children. Keep the child @ForeignKey on the many side; do not store a List column.