Participe do evento ⁠#Android11: apresentação de lançamento da versão Beta no dia 3 de junho.

Como definir dados usando entidades da Room

Ao usar a biblioteca de persistência Room, você define conjuntos de campos relacionados como entidades. Para cada entidade, uma tabela é criada no objeto Database associado para armazenar os itens. É preciso referenciar a classe da entidade por meio da matriz entities na classe Database.

O snippet de código a seguir mostra como definir uma entidade:

Kotlin

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

Java

    @Entity
    public class User {
        @PrimaryKey
        public int id;

        public String firstName;
        public String lastName;
    }
    

Para manter um campo, o Room precisa ter acesso a ele. Você pode tornar o campo público ou fornecer um "getter" e "setter". Se você usa métodos "getter" e "setter", lembre-se de que, na Room, eles são baseados em convenções JavaBeans.

Usar uma chave primária

Cada entidade precisa definir pelo menos um campo como chave primária. Mesmo quando há apenas um campo, ainda é necessário anotá-lo com @PrimaryKey. Além disso, se você quiser que a Room atribua IDs automáticos a entidades, defina a propriedade autoGenerate da @PrimaryKey. Se a entidade tiver uma chave primária composta, será possível usar a propriedade primaryKeys da anotação @Entity, como mostrado no snippet de código a seguir:

Kotlin

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

Java

    @Entity(primaryKeys = {"firstName", "lastName"})
    public class User {
        public String firstName;
        public String lastName;
    }
    

Por padrão, a Room usa o nome da classe como nome da tabela do banco de dados. Caso queira que a tabela tenha um nome diferente, defina a propriedade tableName da anotação @Entity, como mostrado no snippet de código a seguir:

Kotlin

    @Entity(tableName = "users")
    data class User (
        // ...
    )
    

Java

    @Entity(tableName = "users")
    public class User {
        // ...
    }
    

Atenção: os nomes das tabelas no SQLite são indiferentes a maiúsculas.

De forma semelhante à propriedade tableName, a Room usa os nomes dos campos como nomes das colunas no banco de dados. Caso queira que uma coluna tenha um nome diferente, adicione a anotação @ColumnInfo a um campo, como mostrado no snippet de código a seguir:

Kotlin

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

Java

    @Entity(tableName = "users")
    public class User {
        @PrimaryKey
        public int id;

        @ColumnInfo(name = "first_name")
        public String firstName;

        @ColumnInfo(name = "last_name")
        public String lastName;
    }
    

Ignorar campos

Por padrão, a Room cria uma coluna para cada campo definido na entidade. Se uma entidade tem campos que você não quer que persistam, anote-os usando @Ignore, como mostrado no snippet de código a seguir:

Kotlin

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

Java

    @Entity
    public class User {
        @PrimaryKey
        public int id;

        public String firstName;
        public String lastName;

        @Ignore
        Bitmap picture;
    }
    

Em casos em que uma entidade herda campos de uma entidade pai, geralmente é mais fácil usar a propriedade ignoredColumns do atributo @Entity:

Kotlin

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

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

Java

    @Entity(ignoredColumns = "picture")
    public class RemoteUser extends User {
        @PrimaryKey
        public int id;

        public boolean hasVpn;
    }
    

A Room é compatível com vários tipos de anotações que facilitam a pesquisa de detalhes nas tabelas do seu banco de dados. A menos que a minSdkVersion do app seja anterior à 16, use a pesquisa de texto completo.

Compatibilidade com pesquisa de texto completo

Se seu app precisa de acesso rápido a informações do banco de dados por meio da pesquisa de texto completo (FTS, na sigla em inglês), faça com que suas entidades tenham uma tabela virtual que use o módulo de extensão FTS3 ou FTS4 do SQLite (link em inglês). Para usar esse recurso, disponível na Room 2.1.0 e versões mais recentes, adicione a anotação @Fts3 ou @Fts4 a uma determinada entidade, como mostrado no snippet de código a seguir:

Kotlin

    // Use `@Fts3` only if your app has strict disk space requirements or if you
    // require compatibility with an older SQLite version.
    @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 use this type and column name. */
        @PrimaryKey @ColumnInfo(name = "rowid") val id: Int,
        @ColumnInfo(name = "first_name") val firstName: String?
    )
    

Java

    // Use `@Fts3` only if your app has strict disk space requirements or if you
    // require compatibility with an older SQLite version.
    @Fts4
    @Entity(tableName = "users")
    public class User {
        // Specifying a primary key for an FTS-table-backed entity is optional, but
        // if you include one, it must use this type and column name.
        @PrimaryKey
        @ColumnInfo(name = "rowid")
        public int id;

        @ColumnInfo(name = "first_name")
        public String firstName;
    }
    

Em casos em que uma tabela é compatível com conteúdo em vários idiomas, use a opção languageId para especificar a coluna que armazena informações de idioma para cada linha:

Kotlin

    @Fts4(languageId = "lid")
    @Entity(tableName = "users")
    data class User(
        // ...
        @ColumnInfo(name = "lid") val languageId: Int
    )
    

Java

    @Fts4(languageId = "lid")
    @Entity(tableName = "users")
    public class User {
        // ...

        @ColumnInfo(name = "lid")
        int languageId;
    }
    

A Room oferece várias outras opções para definir entidades compatíveis com FTS, incluindo ordenação de resultados, tipos de tokenizer e tabelas gerenciadas como conteúdo externo. Para ver mais detalhes sobre essas opções, consulte a referência FtsOptions.

Indexar colunas específicas

Se seu app precisa ser compatível com versões do SDK que não permitam o uso de entidades com tabelas compatíveis com FTS3 ou FTS4, ainda é possível indexar colunas específicas no banco de dados para acelerar as consultas. Para adicionar índices a uma entidade, inclua a propriedade indices na anotação @Entity, listando os nomes das colunas que você quer incluir no índice ou índice composto. O snippet de código a seguir demonstra esse processo de anotação:

Kotlin

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

Java

    @Entity(indices = {@Index("name"),
            @Index(value = {"last_name", "address"})})
    public class User {
        @PrimaryKey
        public int id;

        public String firstName;
        public String address;

        @ColumnInfo(name = "last_name")
        public String lastName;

        @Ignore
        Bitmap picture;
    }
    

Algumas vezes, determinados campos ou grupos de campos em um banco de dados precisam ser exclusivos. Para aplicar essa exclusividade, defina a propriedade unique de uma anotação @Index como true. A amostra de código a seguir impede que uma tabela tenha duas linhas que contenham o mesmo conjunto de valores para as colunas firstName e lastName:

Kotlin

    @Entity(indices = arrayOf(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?,
        @Ignore var picture: Bitmap?
    )
    

Java

    @Entity(indices = {@Index(value = {"first_name", "last_name"},
            unique = true)})
    public class User {
        @PrimaryKey
        public int id;

        @ColumnInfo(name = "first_name")
        public String firstName;

        @ColumnInfo(name = "last_name")
        public String lastName;

        @Ignore
        Bitmap picture;
    }
    

Incluir objetos baseados em AutoValue

Na Room 2.1.0 e versões mais recentes, é possível usar classes de valor imutável baseadas em Java (link em inglês), anotadas com @AutoValue, como entidades no banco de dados do app. Essa compatibilidade é particularmente útil quando duas instâncias de uma entidade são consideradas iguais caso as colunas tenham valores idênticos.

Ao usar classes anotadas com @AutoValue como entidades, você pode anotar os métodos abstratos da classe usando @PrimaryKey, @ColumnInfo, @Embedded e @Relation. Contudo, ao usar essas anotações, é necessário incluir a anotação @CopyAnnotations todas as vezes para que a Room possa interpretar corretamente as implementações do método geradas de modo automático.

O snippet de código a seguir mostra um exemplo de uma classe anotada com @AutoValue que a Room reconhece como uma entidade:

User.java

    @AutoValue
    @Entity
    public abstract class User {
        // Supported annotations must include `@CopyAnnotations`.
        @CopyAnnotations
        @PrimaryKey
        public abstract long getId();

        public abstract String getFirstName();
        public abstract String getLastName();

        // Room uses this factory method to create User objects.
        public static User create(long id, String firstName, String lastName) {
            return new AutoValue_User(id, firstName, lastName);
        }
    }