Definir dados usando entidades do Room

Ao usar a biblioteca de persistência do Room para armazenar os dados do app, você define entidades para representar os objetos que quer armazenar. Cada entidade corresponde a uma tabela no banco de dados associado do Room, e cada instância de uma entidade representa uma linha de dados na tabela correspondente.

Usar entidades do Room permite definir o esquema do banco de dados sem escrever nenhum código SQL.

Anatomia de uma entidade

Defina cada entidade do Room como uma classe anotada com @Entity. Uma entidade do Room inclui propriedades para cada coluna na tabela correspondente no banco de dados, incluindo uma ou mais colunas que compõem a chave primária.

O código a seguir é um exemplo de uma entidade que define uma tabela User com colunas para ID, nome e sobrenome:

@Entity
data class User(
    @PrimaryKey val id: Int,
    val firstName: String,
    val lastName: String
)

Por padrão, o Room usa o nome da classe como nome da tabela do banco de dados. Se você quiser que a tabela tenha um nome diferente, defina a tableName propriedade da @Entity anotação. Da mesma forma, por padrão, o Room usa os nomes das propriedades como nomes de colunas no banco de dados. Se você quiser que uma coluna tenha um nome diferente, adicione a @ColumnInfo anotação à propriedade e defina a name propriedade. O exemplo a seguir mostra nomes personalizados para uma tabela e as colunas dela:

@Entity(tableName = "users")
data class User(
    @PrimaryKey val id: Int,
    @ColumnInfo(name = "first_name") val firstName: String,
    @ColumnInfo(name = "last_name") val lastName: String
)

Definir uma chave primária

É necessário definir uma chave primária para cada entidade do Room para identificar de maneira exclusiva cada linha na tabela do banco de dados correspondente. Para fazer isso, anote uma única coluna com @PrimaryKey:

@PrimaryKey val id: Int

Definir uma chave primária composta

Caso precise que as instâncias de uma entidade sejam identificadas de maneira exclusiva por uma combinação de várias colunas, defina uma chave primária composta listando essas colunas na propriedade primaryKeys de @Entity:

@Entity(primaryKeys = ["firstName", "lastName"])
data class User(
    val firstName: String,
    val lastName: String
)

Ignorar propriedades

Por padrão, o Room cria uma coluna para cada propriedade definida na entidade. Para impedir que o Room persista uma propriedade, anote-a com @Ignore:

@Entity
data class User(
    @PrimaryKey val id: Int,
    val firstName: String,
    val lastName: String,
    @Ignore val picture: Bitmap? = null
)

Se uma entidade herdar propriedades de uma entidade pai, use a ignoredColumns propriedade da @Entity anotação:

open class User {
    var picture: Bitmap? = null
}

@Entity(ignoredColumns = ["picture"])
data class RemoteUser(
    @PrimaryKey val id: Int,
    val hasVpn: Boolean
) : User()

O Room oferece suporte a várias anotações que permitem pesquisar detalhes nas tabelas do banco de dados.

Compatibilidade com pesquisa de texto completo

Se o app precisar de pesquisa de texto completo (FTS, na sigla em inglês) rápida, faça o backup das entidades com uma tabela virtual. Use a extensão FTS3 ou FTS4 do SQLite ou a extensão FTS5 do SQLite.

Para usar esse recurso, adicione a @Fts3, @Fts4 ou @Fts5 anotação a uma entidade.

// Use `@Fts3` only if your app has strict disk space requirements.
@Fts4
@Entity(tableName = "users")
data class User(
    // Specifying a primary key for an FTS-table-backed entity is optional,
    // but if you include one, it must an INTEGER type and column name "rowid".
    @PrimaryKey @ColumnInfo(name = "rowid") val id: Long,
    @ColumnInfo(name = "first_name") val firstName: String
)

Para personalizar como as informações do banco de dados são tokenizadas em tabelas FTS, use a opção tokenizer. O Room oferece vários tokenizadores integrados por meio de FtsOptions, incluindo TOKENIZER_SIMPLE, TOKENIZER_PORTER e TOKENIZER_UNICODE61:

@Fts4(tokenizer = FtsOptions.TOKENIZER_UNICODE61)
@Entity(tableName = "users")
data class User(
    @PrimaryKey @ColumnInfo(name = "rowid") val id: Long,
    @ColumnInfo(name = "first_name") val firstName: String
)

O Room oferece várias outras opções para definir entidades com apoio do FTS, incluindo ordenação de resultados, remoção de índices de colunas e tabelas gerenciadas como conteúdo externo. Para mais informações sobre essas opções, consulte a FtsOptions referência.

Indexar colunas específicas

Se você estiver usando AndroidSQLiteDriver e precisar oferecer suporte a versões do SDK que não oferecem suporte a entidades com tabelas FTS3, FTS4 ou FTS5, você ainda é possível indexar colunas específicas no banco de dados para acelerar as consultas. Se você usar BundledSQLiteDriver, o Room vai oferecer suporte a todas as versões do FTS independentemente da versão do SDK do Android.

Para adicionar índices a uma entidade, inclua a indices propriedade na @Entity anotação. Liste os nomes das colunas a serem incluídas no índice simples ou composto. O snippet de código a seguir mostra como adicionar índices:

@Entity(indices = [Index(value = ["last_name", "address"])])
data class User(
    @PrimaryKey val id: Int,
    @ColumnInfo(name = "first_name") val firstName: String,
    @ColumnInfo(name = "last_name") val lastName: String,
    val address: String?,
)

Às vezes, algumas colunas ou grupos de colunas em um banco de dados precisam conter valores exclusivos. Para aplicar essa exclusividade, defina a unique propriedade de uma @Index anotação como true. O exemplo de código a seguir mostra como aplicar essa exclusividade:

@Entity(indices = [Index(value = ["first_name", "last_name"], unique = true)])
data class User(
    @PrimaryKey val id: Int,
    @ColumnInfo(name = "first_name") val firstName: String,
    @ColumnInfo(name = "last_name") val lastName: String,
)