Cómo definir datos con entidades de Room

Cuando usas la biblioteca de persistencias de Room para almacenar los datos de tu app, defines entidades para representar los objetos que deseas almacenar. Cada entidad corresponde a una tabla en la base de datos de Room asociada y cada instancia de una entidad representa una fila de datos en la tabla correspondiente.

El uso de entidades de Room te permite definir tu esquema de base de datos sin escribir ningún código de SQL.

Anatomía de una entidad

Define cada entidad de Room como una clase con @Entity como anotación. Una entidad de Room incluye propiedades para cada columna de la tabla correspondiente en la base de datos, incluidas una o más columnas que conforman la clave primaria.

El siguiente código es un ejemplo de una entidad que define una tabla User con columnas para ID, nombre y apellido:

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

De forma predeterminada, Room usa el nombre de la clase como el nombre de la tabla de la base de datos. Si quieres que la tabla tenga un nombre diferente, configura la tableName propiedad de la @Entity anotación. Del mismo modo, Room usa los nombres de las propiedades como nombres de columna en la base de datos de forma predeterminada. Si quieres que una columna tenga un nombre diferente, agrega la @ColumnInfo anotación a la propiedad y configura la name propiedad. En el siguiente ejemplo, se muestran nombres personalizados para una tabla y sus columnas:

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

Cómo definir una clave primaria

Debes definir una clave primaria para cada entidad de Room para identificar de manera única cada fila en la tabla de base de datos correspondiente. Para ello, anota una sola columna con @PrimaryKey:

@PrimaryKey val id: Int

Cómo definir una clave primaria compuesta

Si necesitas que las instancias de una entidad se identifiquen de forma única mediante una combinación de varias columnas, puedes definir una clave primaria compuesta si enumeras esas columnas en la propiedad primaryKeys de @Entity:

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

Ignorar propiedades

De forma predeterminada, Room crea una columna para cada propiedad definida en la entidad. Para evitar que Room conserve una propiedad, anótala con @Ignore:

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

Si una entidad hereda propiedades de una entidad principal, usa la ignoredColumns propiedad de la @Entity anotación:

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

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

Room admite varias anotaciones que te permiten buscar detalles en las tablas de tu base de datos.

Cómo admitir la búsqueda en el texto completo

Si tu app requiere una búsqueda rápida en el texto completo (FTS), respalda tus entidades con una tabla virtual. Usa la extensión SQLite FTS3 o FTS4 o la extensión SQLite FTS5.

Para usar esta capacidad, agrega la @Fts3, @Fts4 o @Fts5 anotación a una entidad.

// 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 la forma en que se tokeniza la información de la base de datos en las tablas de FTS, usa la opción tokenizer. Room proporciona varios tokenizadores integrados a través de FtsOptions, incluidos TOKENIZER_SIMPLE, TOKENIZER_PORTER y 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
)

Room ofrece varias opciones para definir entidades respaldadas por FTS, entre ellas el orden de los resultados, la eliminación de índices de columnas y las tablas que se administran como contenido externo. Para obtener más información sobre estas opciones, consulta la FtsOptions referencia.

Columnas específicas del índice

Si usas AndroidSQLiteDriver y necesitas admitir versiones de SDK que no admiten entidades respaldadas por tablas FTS3, FTS4 o FTS5, igual puedes indexar algunas columnas de la base de datos para agilizar las consultas. Si usas BundledSQLiteDriver, Room admite todas las versiones de FTS independientemente de la versión del SDK de Android.

Para agregar índices a una entidad, incluye la indices propiedad en la @Entity anotación. Enumera los nombres de las columnas que deseas incluir en el índice o en el índice compuesto. En el siguiente fragmento de código, se muestra cómo agregar í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?,
)

A veces, ciertas columnas o grupos de columnas de una base de datos deben contener valores únicos. Para aplicar esta exclusividad, configura la unique propiedad de una @Index anotación como true. En la siguiente muestra de código, se muestra cómo aplicar esta exclusividad:

@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,
)