Android Room DataBase(二)

前言:

1、在学习本篇之前,请确保你读过Android Room DataBase(一),或者知道如何定义Room的三大组件以及如何简单的使用它们。
2、本篇,将着重讲解Room的Entity(表)。包含如何定义Entity的主键、索引、唯一性 and so on。
3、Sql的基本语法:http://www.w3school.com.cn/sql/index.asp

一、在Room数据库中创建一张表(Entity)。

在Room中,每一个表以一个Java类的形式来表现。但是,必须在该类的类定义的前一行,加上**@Entity**注解。用以表示该类是Room的一个Entity。下面代码,向你展示,一个Entity是如何被定义:

@Entity
class User {

    @PrimaryKey
    public int id;

    public String firstName;
    public String lastName;

    @Ignore
    Bitmap picture;
    
}

上面的代码,主要有三个注解,需要进行解释,它们分别是:

1、@Entity,该注解,写在类的定义的前一行,用于表示该类是Room的一个Entity。

2、@PrimaryKey,该注解,写在字段的定义的前一行,用于表示该字段是该Entity的主键。

3、@Ignore,该注解,写在字段的定义的前一行,用于忽略掉那些不需要保存到表中的字段。

这里需要注意的是,Entity类的字段的访问权限,可以是私有的。但是,为了确保其对应的Dao能够访问该字段。需要给私有字段,添加Setter和Getter。而且,它们的命名,必须遵循JavaBean的格式。Android Studio有自动创建Setter和Getter的功能,不懂请百度一下

另外,Entity类允许,存在不带参的默认构造方法或是带部分或全部参数的构造方法。这里的部分参数或全部参数的参数,指的是,该Entity类里的字段。注意,这些参数必须与Entity里的字段相同

二、定义及使用表中的主键(PrimaryKey)。

正如“一”中所讲,只要在字段的定义的前一行,添加@PrimaryKey注解即可定义一个表中的主键。
但是,这里有几个点,需要注意:

**1、Entity必须包含至少一个主键。**每一个Entity,都必须有至少一个主键,哪怕这个Entity里面什么都没有,都得添加一个主键。
2、主键ID的自增(autoGenerate)。只要设置PrimaryKey的autoGenerate属性为true即可。

@PrimaryKey(autoGenerate = true) 
private int id; 

3、联合主键(primaryKeys)。与单主键不同的是,联合主键的定义,是作为@Entity的属性的形式,被定义的。并且,关键字是primaryKeys,不是primaryKey,多了一个s。代码如下:

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

    public String firstName;
    public String lastName;

    @Ignore
    Bitmap picture;
}

4、自定义表名(tableName)。

你可以通过@Entity的tableName属性,来定义一个与类名不同的表名。代码如下:

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

5、自定义字段名(ColumnInfo)。

你可以通过@ColumnInfo注解的name属性,来定义一个与字段名不同的列名。代码如下:

@Entity
public class User {

    @ColumnInfo(name = "first_name")
    private String firstName;
    
    @ColumnInfo(name = "last_name")
    private String lastName;
}

三、创建索引与唯一性约束。

我们可以通过创建索引,来提高查询的效率,其原理是索引原理。同时,可以创建字段的唯一性约束,来避免创建相同的数据。因为在一张表中,除了主键(id)字段的每条数据都是不同之外,有可能还存在其它字段的数据也不允许重复,比如身份证号码,这时就需要添加唯一性约束。

1、索引(indices)

创建索引的根本目的,是提高查询的效率。那么,如何在Entity中,创建索引呢?

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

    public String firstName;
    public String address;

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

    @Ignore
    Bitmap picture;
}

2、唯一性约束(unique)

有时候,我们可能想要某一字段,或多个字段的组合的数据,在表中是唯一的,不重复的。那么,我们可以使用唯一性约束。代码如下:

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

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

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

    @Ignore
    Bitmap picture;
}

四、创建外键(foreignKeys)。

需要注意的是: RoomDataBase不支持Entity里面包含另一个Entity。即便在服务端,这种做法不仅正确,而且可以很好的运行。因为在服务端,这种包含关系,是采用懒(延后)加载机制的,即在需要的时候,再查询。但在客户端,就不是这么一回事了。因为在UI线程中做耗时操作,会导致ANR。所以,假如Room支持这一种形式的话,在延时加载另一个Entity的时候,就有可能出现ANR或者明显的卡顿。所以,Room明令禁止Entity中包含,某一字段是另一种Entity类型。

但是,Room 允许通过创建外键的形式,来绑定多个Entity之间的关系,来确保数据的完整性。让我们来看看,如何创建外键:

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

    public String title;

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

五、在Entity中创建自定义类型字段(Embedded)。

注意:在Entity中创建自定义类型字段,并不意味着,你可以在Entity中创建另一种Entity类型字段。Room,明令禁止多个Entity之间的相互嵌套!

有时候,我们可能想要在Entity中创建一个自定义字段,比如,在User类中,再加一个Address类**(非Entity)的字段。那么,该怎么办呢?很简单,Room提供了一个注解@Embedded**。只需要在自定义类型的字段的上一行,添加该注解即可。废话不多说,Show you code:

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

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

@Entity
class User {
    @PrimaryKey
    public int id;

    public String firstName;

    @Embedded
    public Address address;
}

有几点需要注意的:

1、此时,数据表User,并没有一列叫做address的。而是一共有6列数据,分别是:id, firstName, street, state, city, post_code。

2、自定义类型字段里面,可以嵌套另一个自定义类型字段。

基于上面的情况,可能会出现一种情况,就是当一个Entity中存在多个相同的自定义类型的时候,你可能想要为区分每一个自定义类型的字段。这样说,可能不好理解,举个例子,考虑一下这种情况:

1、有一个普通Java类Coordinate,代表坐标,包含两个表示经纬度的字段:longitudelatitude

2、有一个Entity类Coordinates,代表多个国家的坐标,包含两个类型为Coordinate的字段,分别表示中国和英国的坐标:chinaCoordinateenglandCoordinate

如代码所示:

/**
 * @Author 李岳锋
 * @CreateTime 2018/2/23
 * @Description 讨论@Embedded的prefix属性的作用
 **/
@Entity
public class Coordinates {

    // 代表中国的坐标,存到表中后,该类的字段会变成latitude和longitude
    @Embedded
    private Coordinate chinaCoordinate;

    // 代表英国的坐标,存到表中后,该类的字段会变成latitude和longitude
    @Embedded
    private Coordinate englandCoordinate;

}

// 代表坐标
class Coordinate{

    @ColumnInfo(name = "latitude")
    private long latitude;

    @ColumnInfo(name = "longitude")
    private long longitude;
}

基于上面的知识,我们可以知道。Entity表只会存在两个字段,分别是latitude和longitude。这样,我们就无法,分别的为中国和英国的坐标做出区分。那当我们想区分二者时,该怎么做呢?同样地,Room为 @Embedded注解提供了一个prefix属性。通过设置该属性,就可以进行区分,确保表中,存在不同的字段。废话不多说,看代码:

/**
 * @Author 李岳锋
 * @CreateTime 2018/2/23
 * @Description 讨论@Embedded的prefix属性的作用
 **/
@Entity
public class Coordinates {

    // 代表中国的坐标,存到存储库里面后,该类的字段会变成CN_latitude和CN_longitude
    @Embedded(prefix = "CN_")
    private Coordinate chinaCoordinate;

    // 代表英国的坐标,存到存储库里面后,该类的字段会变成UK_latitude和UK_longitude
    @Embedded(prefix = "UK_")
    private Coordinate englandCoordinate;

}

// 代表坐标
class Coordinate{

    @ColumnInfo(name = "latitude")
    private long latitude;

    @ColumnInfo(name = "longitude")
    private long longitude;
}

修改后,Coordinates 表中将会存在四个字段,分别是:CN_latitude、CN_longitude、UK_latitude和UK_longitude。


到此为止,我们已经讲解完Entity的相关知识。下一篇,我们会讲解Dao的相关知识。坚持,就是胜利,不是吗?好了,后续再见! Thank you for reading my posted, Happy New Chinese Year!

Dao:http://blog.csdn.net/l_o_s/article/details/79388408
RoomDataBase基础入门:http://blog.csdn.net/l_o_s/article/details/79346426
官方文档(传送门):https://developer.android.com/training/data-storage/room/defining-data.html

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值