Detailed explanation of Android Room data entity class

I. Introduction

In the process of using the Room library, define data entity classes to represent the data objects that need to be stored. Each data entity class corresponds to a table in the associated database. Each field of the data entity class corresponds to a column in the table. The data entity class objects correspond to a row of data in the table (if you don't know the Room library, please read: Introduction to Android Room Library Basics ). This means that using the Room data entity class, the database schema can be defined without any SQL statements.

Second, the detailed explanation of the Room data entity class

2.1 Room data entity class definition

Room defined data entity class, use data classthe keyword, and use the @Entityannotation label. As shown in the following code:

@Entity
class User(@PrimaryKey val uid: Int, val name: String, val age: Int)
Note:
1. In order to keep the attribute in the entity class as a column of the table, the Room must have permission to access this attribute. If the Room cannot access the attribute, the attribute will not become a column in the corresponding database table. Access properties can be modified to set public, or to provide attributes getter()and setter()methods to ensure Room access attribute data entity class.
2. If you use Kotlin development, the attribute defined in the constructor, the corresponding column in the table structure is NOT NULL(not nullable), if you need to list as nullable, then define the attribute inside the data class and define the attribute value It can be empty, as shown below.
// 该数据实体类对应的表结构为 CREATE TABLE teacher(tid INTEGER NOT NULL PRIMARY KEY, name TEXT NOT NULL, subject TEXT);
@Entity
data class Teacher(@PrimaryKey val tid: Int, @ColumnInfo val name: String) {
    // 在类内部定义属性,并定义为可为空,这样生成的表结构中,对应的列也是可为空
    @ColumnInfo  var subject: String? = null
}

2.2 Specify the table name corresponding to the data entity class

By default, Room will provide the table name (table name in the database is actually not case-sensitive) according to the class entity class, developers can also be in the @Entitynotes by tableNamethe specified table name argument, so when creating the Room table is specified Name naming. As shown in the following sample code:

@Entity(tableName = "users")
data class User(@PrimaryKey val uid: Int, val name: String, val age: Int)
Note: The name of the database table is not case sensitive.

2.3 Set the primary key of the data table

Each data entity class must define a primary key to ensure that each row of data in the data table is unique. Can specify one or more columns as the primary key, set the primary key can be used to define the data entity class attributes @PrimaryKeyannotation designated (specified single column as the primary key is the recommended method), may be the definition of the data entity class in the @Entityannotation by primaryKeysattribute declaration (specify multiple columns compositions this method is recommended as the primary key, @Entityannotation primaryKeysproperty is an array). As shown in the following code example:

// 在数据实体类的属性使用 @PrimaryKey 注解声明主键
@Entity(tableName = "users")
data class User(@PrimaryKey val uid: Int, val name: String, age: Int)

// 在 `@Entity` 注解中通过 `primaryKeys` 属性声明主键
@Entity(tableName = "users", primaryKeys = ["uid"])
data class User(val uid: Int, val name: String, val age: Int)

If you specify a single column as the primary key, you can also set the primary key value to auto-increment, so that you do not need to specify the value of the primary key in the data entity class when instantiating the data entity class object. By @PrimaryKeyannotation autoGenerateproperty value is set trueto, but be aware that if you set the main key increment, then the primary key attributes do not appear in the constructor parameters (so no need to set the property value when instantiating, by the database Achieve self-increment). As shown in the following code example:

@Entity(tableName = "users")
data class User(@ColumnInfo(name = "name") val name: String, val age: Int) {
    // 自增的主键,在类内部定义,不要出现在构造函数的参数中,这样在实例化时才不需要设置改值,
    @PrimaryKey(autoGenerate = true) var uid: Int = 0
}

2.4 Specify the column names of the table

By default, Room will be used as the name of the corresponding column of data based on the attribute name of the entity class, if developers want to specify a different name, you can use the @ColumnInfoannotation nameattribute specifies the name of the column. As shown in the following sample code:

@Entity(tableName = "users", primaryKeys = ["uid"])
data class User(val uid: Int, @ColumnInfo(name = "name") val name: String, val age: Int)
Note: The column names of the database table are not case sensitive.
Tip: When defining a data entity class, you may have questions. If you want to define a field as the primary key, but also want to specify the column name of the primary key column in the table, what should you do? One way is through the @Entitydesignated primary key, then use on the primary key attribute @ColumnInfospecifies the name of the column primary key column notes. Another method is to use the annotation overlay, that is used while on the primary key attribute @PrimaryKeycomments and @ColumnInfoannotations. The following example:
@Entity(tableName = "users")
data class User(@PrimaryKey @ColumnInfo(name = "id") val uid: Int, @ColumnInfo(name = "name") val name: String, val age: Int)

2.5 Ignore attributes

As mentioned earlier, in order to keep the attribute in the entity class as a column of the table, Room must have permission to access this attribute. What if the attribute of the data entity class can be accessed by Room but does not want to be a column in the data table? Actually very simple, just use @Ignoreannotations to mark the property, so that, even if Room able to access the property, the property will be ignored, not as a data table. As shown in the following example:

@Entity(tableName = "users")
data class User(@ColumnInfo(name = "name") val name: String, val age: Int) {
    // 自增的主键,在类内部定义,不要出现在构造函数的参数中,这样在实例化时才不需要设置改值,
    @PrimaryKey(autoGenerate = true) var uid: Int = 0

    @Ignore var avatar: String = ""
}

By querying the table structure of the database, you can see the effect. As shown below:

View table structure

2.6 Provide table search support

Room provides multiple types of annotations to make it easier for you to search for the contents of the tables in the database. Unless the application is miniSdkVersionless than 16, otherwise use full-text search (FTS).

2.6.1 Full-text search (FTS) support

If your application needs to quickly access database information through full-text search (FTS), please use virtual tables (using FTS3 or FTS4 SQLite extension modules) to provide support for your data entity classes. If you need to use version 2.1.0 and above Room in this feature, added in a statement when the entity class data @Fts3or @Fts4annotations. As shown in the following sample code

@Fts4
@Entity(tableName = "users")
// 数据实体类定义了主键,主键列名必须以 rowid 为列名,数据类型为 INTEGER
data class User(@PrimaryKey @ColumnInfo(name = "rowid") val uid: Int, @ColumnInfo(name = "name") val name: String, val age: Int)
Notes:
1. Enable full-text search (FTS) of the table, must be based on rowidthe name, INTEGERthe column as the primary key format of the data, if the data corresponding to the table data entity class FTS enabled the definition of the class of the primary key, then the primary key must be specified Column name and data type;
2. If your application has strict disk space requirements or needs to support a lower version of SQLite database, please use it @Fts3.

If the contents stored in the table to support multiple languages, the use of @Fts4annotation languageIdproperty represents the attribute specifies the language category (only for FTS4), shown in the code example below:

@Fts4(languageId = "motherLang")
@Entity(tableName = "users")
data class User(@PrimaryKey @ColumnInfo(name = "rowid") val uid: Int, @ColumnInfo(name = "name") val name: String, val age: Int, val motherLang: String)
Note: Room provides a variety of options for defining entity classes that support FTS. These options include result sorting, parser type, and tables used as external content management. For more details, please refer to: FtsOptions Reference Document

2.6.2 Index specific columns

If the SDK version supported by your application does not allow the use of data entity classes ( miniSDKVersionless than 16) supported by FTS3 or FTS4 , you can still index certain columns to speed up the query. Need to add to the index when defining the data entity class, you can be @Entityannotated indicesto specify the index to be added to (or composite indexes) column name attribute. As shown in the following example:

@Entity(tableName = "users", indices = [Index("rowid", "name")])
data class User(@PrimaryKey @ColumnInfo(name = "rowid") val uid: Int, @ColumnInfo(name = "name") val name: String, val age: Int)

Sometimes, certain field or group of fields in the database must be unique, you can be @Indexannotated uniqueproperty value is set trueto forcibly set the property or property group unique. As shown in the following example:

@Entity(tableName = "users", indices = [Index(value = ["rowid", "name"], unique = true)])
data class User(@PrimaryKey @ColumnInfo(name = "rowid") val uid: Int, @ColumnInfo(name = "name") val name: String, val age: Int)

Add 2.7 based on AutoValueobject

Note: This function is designed for Java-based entity classes. Kotlin-based entity classes want to achieve the same purpose. It is best to use data classes.

In later versions 2.1.0 Room, you can use the Java-based immutable value classes, immutable value class is used in the application database @AutoValueentity classes marked. This function is very useful when used to compare whether two entity objects are equal (whether the value of each column is exactly the same).

When @AutoValuethe time annotation annotated class as an entity class, you can use the @PrimaryKey, @ColumnInfo, @Embedded,and @Relationabstract methods of the class tagging, when using these notes, must be added at the same time each @CopyAnnotationscomment to Room can automatically generate the correct interpretation of these methods of implementation. As shown in the following code:

  • User.java
@AutoValue
@Entity
public abstract class User {
    // 支持的注解中必须每次都包含 `@CopyAnnotations` 注解
    @CopyAnnotations
    @PrimaryKey
    public abstract long getId();

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

    // Room 使用这个工厂类生成 User 对象.
    public static User create(long id, String firstName, String lastName) {
        return new AutoValue_User(id, firstName, lastName);
    }
}

3. Detailed explanation of common annotations in data entity class definition

3.1 @EntityAnnotation

Used to annotate the data class, the following are the attributes contained in the annotation.

Field Nametype of dataDefaultsDescription
tableNameString-Specify the table name, if not specified, use the data class name as the table name
indices@Index-Used to specify the index list
inheritSuperIndicesBooleanfalseIf set to true, all indexes defined in the parent class will be inherited
primaryKeysString []-Used to specify the primary key
foreignKeys@ForeignKey[]-Used to specify foreign keys
ignoredColumnsString []-Used to specify attributes ignored by Room, attributes ignored by Room will not appear in the table

3.2 @PrimaryKeyAnnotation

The attribute used to annotate the data class is the primary key. The following are the attributes contained in the annotation.

Field Nametype of dataDefaultsDescription
autoGenerateBooleanfalseIf set to true, when defining the data entity class object, the primary key does not need to be assigned, and the value will be automatically incremented

3.3 @ColumnInfoAnnotation

Used to mark the attribute details of the data class (attributes in the database table). The following are the attributes contained in the annotation.

Field Nametype of dataDefaultsDescription
nameString-Specify the column name, if not specified, use the attribute name of the data class as the column name
indexBooleanfalseSpecify the column as an index
collateIntUNSPECIFIED(1)Used to specify the type of data collation for the column
defaultValueStringVALUE_UNSPECIFIED([value-unspecified])Used to specify the default value of the column

Four, summary

This chapter introduces the use of the Room data entity class in detail. The clever use of annotations and class structure can achieve different table structures. There are more clever usages that may not be covered in this article. If readers have new discoveries, please leave a message.