Android Architecture Component Room持久化数据库 (二)使用Room实体定义数据

版权声明:本文为博主原创文章,欢迎大家转载!

但是转载请标明出处: https://blog.csdn.net/t000818/article/details/84258618 ,本文出自:【唐宏宇的博客】


使用Room持久性库时,可以将相关字段集定义为实体。对于每个实体,在关联的Database对象中创建一个表来保存项目。必须通过Database类中的entities数组引用实体类。

注意:  要在应用程序中使用实体,请将  Architecture Components artifacts 添加到应用程序的build.gradle文件中。

以下代码段显示了如何定义实体:

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;
}

如果要持久化一个字段,Room必须能够访问它。您可以将字段设为public,也可以为其提供getter和setter。如果使用getter和setter方法,请记住它们基于Room中的JavaBeans约定。

注意:实体可以有一个空构造函数 (如果相应的 DAO 类可以访问每个持久化字段), 也可以有一个构造函数, 其参数包含与实体中的字段的类型和名称相匹配的类型和名称。Room 还可以使用完整或部分构造函数, 例如只接收某些字段的构造函数

 

定义主键

每个实体必须至少定义一个字段作为主键。即使只有一个字段,您仍然需要使用@PrimaryKey注释来注释该字段。此外,如果您希望Room为实体分配自动ID,您可以设置@ PrimaryKey的autoGenerate属性。如果实体具有复合主键,则可以使用@Entity批注的primaryKeys属性,如以下代码段所示:

Kotlin写法:

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

Java写法:

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

默认情况下,Room使用类名作为数据库表名。如果希望表具有不同的名称,请设置@Entity批注的tableName属性,如以下代码段所示:

Kotlin写法:

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

Java写法:

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

警告:SQLite中的表名称不区分大小写。

 

与tableName属性类似,Room使用字段名称作为数据库中的列名称。如果希望列具有不同的名称,请将@ColumnInfo注释添加到字段中,如以下代码段所示:

Kotlin写法:

@Entity(tableName = "users")
data class User (
    @PrimaryKey var id: Int,
    @ColumnInfo(name = "first_name") var firstName: String?,
    @ColumnInfo(name = "last_name") var 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;
}

 

忽略字段

默认情况下,Room会为实体中定义的每个字段创建一列。如果实体有想忽略的字段,则可以使用@Ignore它们进行注释
忽略,如下面的代码片段所示:

Kotlin写法:

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

Java写法:

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

    public String firstName;
    public String lastName;

    @Ignore
    Bitmap picture;
}

如果实体从父实体继承字段,则通常使用@Entity属性的ignoredColumns属性:

Kotlin写法:

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

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

Java写法:

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

    public boolean hasVpn;
}

 

提供表搜索支持

Room支持多种类型的注释,使你可以更轻松地搜索数据库表中的详细信息。除非您的应用的minSdkVersion小于16,否则请使用全文搜索。

 

支持全文搜索

如果您的应用程序需要通过全文搜索(FTS)快速访问数据库信息,请让您的实体由使用FTS3或FTS4 SQLite extension module.的虚拟表支持。要使用Room 2.1.0及更高版本中提供的此功能,请将@Fts3 或@Fts4 注释添加到给定实体,如以下代码段所示:

Kotlin写法:

// 仅当你的应用程序具有严格的磁盘空间要求或者您需要与较旧的SQLite版本兼容时,才使用`@ Fts3`。
@Fts4
@Entity(tableName = "users")
data class User(
    /* 为FTS表支持的实体指定主键是可选的,但是
       如果包含一个,则必须使用此类型和列名称 */
    @PrimaryKey @ColumnInfo(name = "rowid") var id: Int,
    @ColumnInfo(name = "first_name") var firstName: String?
)

Java写法:

// 仅当你的应用程序具有严格的磁盘空间要求或者您需要与较旧的SQLite版本兼容时,才使用`@ Fts3`
@Fts4
@Entity(tableName = "users")
public class User {
    // 为FTS表支持的实体指定主键是可选的,但是如果包含一个,则必须使用此类型和列名称
    @ColumnInfo(name = "rowid")
    public int id;

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

注意: 启用FTS的表始终使用INTEGER类型的主键和列名“rowid”。如果您的FTS表支持的实体定义主键,则它必须使用该类型和列名称.

如果表支持多种语言的内容,请使用languageId选项指定存储每行语言信息的列:

Kotlin写法:

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

Java写法:

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

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

Room提供了其他几个用于定义FTS支持的实体的选项,包括结果排序,tokenizer类型和作为外部内容管理的表。有关这些选项的更多详细信息,请参阅FtsOptions参考。

 

索引表中特定的列

如果你的应用必须支持的SDK版本不允许使用FTS3或FTS4表支持的实体,仍然可以索引数据库中的某些列以加快查询速度。要向实体添加索引,请在@Entity注解中添加indices属性,列出要包含的索引或复合索引中的列的名称。以下代码片段演示了此注截过程:

Kotlin写法:

@Entity(indices = arrayOf(Index(value = ["last_name", "address"])))
data class User(
    @PrimaryKey var id: Int,
    var firstName: String?,
    var address: String?,
    @ColumnInfo(name = "last_name") var lastName: String?,
    @Ignore var 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;
}

有时,数据库中的某些字段或字段组必须是唯一的。您可以通过在@Index 注解中设置unique属性索引注解为true,来强制使这些属性保持唯一性。以下代码示例可防止表具有两行,这些行包含firstName和lastName列的相同值集:

Kotlin写法:

@Entity(indices = arrayOf(Index(value = ["first_name", "last_name"],
        unique = true)))
data class User(
    @PrimaryKey var id: Int,
    @ColumnInfo(name = "first_name") var firstName: String?,
    @ColumnInfo(name = "last_name") var 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;
}

 

包括基于AutoValue的对象

注意:此功能仅适用于基于Java的实体。要在基于Kotlin的实体中实现相同的功能,最好使用data classes数据类。

在2.1.0及更高版本的Room中,您可以使用基于Java的 immutable value classes不可变值类(使用@AutoValue进行注解)作为应用程序数据库中的实体。如果实体的两个实例的列包含相同的值,则此支持特别有用

使用带@AutoValue注释的类作为实体时,可以使用@PrimaryKey,@ ColumnInfo,@ Embedded和@Relation注解类的抽象方法。但是,在使用这些注释时,每次都必须包含@CopyAnnotations注释,以便Room可以正确解释方法的自动生成实现。

以下代码段显示了一个使用@AutoValue注释的类的示例,Room将其识别为实体

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);
    }
}

 

定义对象间的关系

由于SQLite是关系数据库,因此您可以指定对象之间的关系。尽管大多数对象关系映射库允许实体对象相互引用,但Room明确禁止这样做。要了解此决策背后的技术推理,请参阅了解Room为何不允许对象引用Understand why Room doesn't allow object references

即使您不能使用直接关系,Room仍允许您在实体之间定义外键约束。

例如,如果存在另一个名为Book的实体,则可以使用该实体定义其与User实体的关系@ForeignKey注解,如下面的代码片段所示:

Kotlin写法:

@Entity(foreignKeys = arrayOf(ForeignKey(
            entity = User::class,
            parentColumns = arrayOf("id"),
            childColumns = arrayOf("user_id"))
       )
)
data class Book(
    @PrimaryKey var bookId: Int,
    var title: String?,
    @ColumnInfo(name = "user_id") var userId: Int
)

Java写法:

@Entity(foreignKeys = @ForeignKey(entity = User.class,
                                  parentColumns = "id",
                                  childColumns = "user_id"))
public class Book {
    @PrimaryKey
    public int bookId;

    public String title;

    @ColumnInfo(name = "user_id")
    public int userId;
}

外键非常强大,因为它们允许您指定更新引用实体时发生的情况。例如,如果通过在@ForeignKey 注解中包含onDelete = CASCADE ,当相应的User实例被删除是,则可以通知SQLite删除该用户的所有书籍。

注意:SQLite将 @Insert(onConflict = REPLACE)作为一组REMOVE和REPLACE操作处理,而不是单个UPDATE操作。这种替换冲突值的方法可能会影响您的外键约束。有关更多详细信息,请参阅ON_CONFLICT子句的 SQLite documentation文档。

 

创建嵌套对象

有时,您希望在数据库逻辑中将实体或普通旧Java对象(PO​​JO)表达为一个整体,即使该对象包含多个字段。在这些情况下,您可以使用@Embedded 注解来表示对象你想“分解成表格中的子字段”。然后,您可以像查找其他单个列一样查询嵌入字段。

例如,我们的User类可以包含Address类型的字段,它表示名为street,city,state和postCode的字段的组合。若要在表中单独存储组合列,请在User类中包含一个带@Embedded注解的Address字段,如下面的代码片段所示

Kotlin写法:

data class Address(
    var street: String?,
    var state: String?,
    var city: String?,
    @ColumnInfo(name = "post_code") var postCode: Int
)

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

Java写法:

public class Address {
    public String street;
    public String state;
    public String city;

    @ColumnInfo(name = "post_code")
    public int postCode;
}

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

    public String firstName;

    @Embedded
    public Address address;
}

上面表示User对象的表包含具有以下名称的列:id,firstName,street,state,city和post_code。

注意:嵌入字段还可以包含其他嵌入字段

如果实体具有多个相同类型的嵌入字段,则可以通过设置prefix属性使每个列保持唯一。然后,Room将提供的值添加到嵌入对象中每个列名称的开头。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值