定义和查询一对多关系

两个实体之间的一对多关系是指这样一种关系:父实体的每个实例对应于子实体的零个或多个实例,但子实体的每个实例只能恰好对应于父实体的一个实例。

在音乐在线影音应用示例中,假设用户可以将其歌曲整理到播放列表中。每个用户可以创建任意数量的播放列表,但每个播放列表只能由一个用户创建。因此,User 实体和 Playlist 实体之间存在一对多关系。

如需在数据库中定义和查询一对多关系,请按以下步骤操作:

  1. **定义关系**:为这两个实体分别创建类, 并让子实体引用父实体的主键。
  2. 查询实体:在新数据类中对关系进行建模 并实现一个用于检索相关数据的函数。

定义关系

如需定义一对多关系,请先为每个实体分别创建一个类。与一对一关系一样,子实体必须包含一个变量,且该变量是对父实体的主键的引用。

@Entity
data class User(
    @PrimaryKey val userId: Long,
    val name: String,
    val age: Int
)

@Entity
data class Playlist(
    @PrimaryKey val playlistId: Long,
    val userCreatorId: Long,
    val playlistName: String
)

查询实体

如需查询用户列表和对应的播放列表,您必须先在两个实体之间建立一对多关系。

如需对关系进行建模,请创建一个新的数据类。此类中的每个实例都包含父实体的一个实例和与之对应的所有子实体实例的列表。 将 @Relation 注释添加到表示子实体列表 的属性。将 parentColumns 设置为父实体的主键列的名称,并将 entityColumns 设置为引用父实体主键的子实体的列的名称。

data class UserWithPlaylists(
    @Embedded val user: User,
    @Relation(
        parentColumns = ["userId"],
        entityColumns = ["userCreatorId"]
    )
    val playlists: List<Playlist>
)

最后,向数据访问对象 (DAO) 类添加一个函数,用于返回将父实体与子实体配对的数据类的所有实例。 添加 @Transaction 注释,以便 Room 以原子方式执行整个操作 。此注释是必需的,因为该函数需要 Room 运行两次查询。

@Transaction
@Query("SELECT * FROM User")
suspend fun getUsersWithPlaylists(): List<UserWithPlaylists>

复合键

如果您使用复合键定义关系,请在 parentColumnsentityColumns 中指定多个列。parentColumns 中的列的顺序必须与 entityColumns 中的列的顺序相匹配。

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

@Entity
data class Playlist(
    @PrimaryKey val playlistId: Long,
    val userFirstName: String,
    val userLastName: String,
    val playlistName: String
)

data class UserWithPlaylists(
    @Embedded val user: User,
    @Relation(
        parentColumns = ["firstName", "lastName"],
        entityColumns = ["userFirstName", "userLastName"]
    )
    val playlists: List<Playlist>
)