Escriu per cercar…

Relation

Model one-to-many and many-to-many relationships in Room using @ForeignKey and retrieve related data with @Relation (and @Junction)

Aquesta pàgina encara no s'ha traduït — es mostra en l'idioma original:English

Introduction

Room fully supports foreign key relationships via @ForeignKey. This sets up the foreign keys in the appropriate tables.

Room also has a @Relation annotation to retrieve related data, though it does not directly add navigation properties to your entities.

One-to-Many Relations

Let’s imagine an app for a book catalog.

The catalog is divided into categories, and categories can have books.

We need a Category entity to model categories and a Book entity to model books, along with a one-to-many relationship between Category and Book.

Category itself does not need anything special. It is just an ordinary Room entity:

kotlin
@Entity(tableName = "category")
data class Category(
    @PrimaryKey
    val code: String,
    val name: String
)

Note that it does not have a List or other collection of Book objects.

You cannot ask a category for its books by navigating from the entity itself.

Foreign Keys

Configuring the Foreign Key

Book, and our DAO, are where things start to get interesting.

The Book class, in isolation, is about as plain as Category:

kotlin
@Entity(
    tableName = "book",
    foreignKeys = [ForeignKey(
        entity = Category::class,
        parentColumns = arrayOf("code"),
        childColumns = arrayOf("category"),
        onDelete = CASCADE
    )]
)
data class Book(
    @PrimaryKey
    val isbn: String,
    val title: String,
    @ColumnInfo(index = true) var category: String
)

We declare an index on category, and, as the name suggests, this holds the code primary key of the Category that is associated with this Book.

Note that Book does not have an actual property for the Category, just its key.

The @Entity annotation also has an array of @ForeignKey annotations (foreignKeys).

Each @ForeignKey annotation has at least three primary properties:

entityPoints to the entity class that represents the “one” side of the one-to-many relation
parentColumnsIdentifies the column(s) in the parent table that represent the primary key
childColumnsIdentifies the column(s) in the child table that represent the parent’s primary key

In this case, Category has a single-property primary key, so parentColumns points to that (code), while childColumns points to the corresponding column in Book (category).

Cascades on Updates and Deletes

You can place onUpdate and onDelete properties on a @ForeignKey annotation. These indicate what actions should be taken on this entity when the parent of the foreign key relationship is updated or deleted.

There are five possibilities, denoted by ForeignKey constants:

Constant NameIf the Parent Is Updated or Deleted…
NO_ACTION…do nothing
CASCADE…update or delete the child
RESTRICT…fail the parent’s update or delete, unless there are no children
SET_NULL…set the foreign key value to null
SET_DEFAULT…set the foreign key value to the column(s) default value

NO_ACTION is the default, though CASCADE is a popular choice for onDelete.

In the Book entity’s @ForeignKey, we use onDelete = CASCADE, so if a Category is deleted, all of its associated Book rows are deleted from the book table.

For many operations, our DAO is no different from others: we can insert, update, delete, and query entities.

However, from a property standpoint, books and categories only have keys, not references to other entities.

So, by default, if we have a @Query function that returns a Book, we have to execute a separate @Query function to look up its Category via the code.

And if we have a @Query function that returns a Category, we have to have another @Query function to retrieve all books associated with that Category.

A @Query does not have to return entities. It can return any type that Room can map from the query result. So, we can declare a custom data class for a @Query response, such as this CategoryAndBooks class:

kotlin
data class CategoryAndBooks(
    @Embedded
    val category: Category,
    @Relation(
        parentColumn = "code",
        entityColumn = "category"
    )
    val books: List<Book>
)

Estàs llegint una vista prèvia.

Inicia sessió per llegir l'article complet. Qualsevol compte obre 4 articles gratuïts al mes; l'alumnat i el professorat llegeixen les pàgines del seu curs sense límit.

Inicia sessió