如何在房间持久性库中使用外键

Posted

技术标签:

【中文标题】如何在房间持久性库中使用外键【英文标题】:how to use foreign key in Room persistence library 【发布时间】:2018-05-10 17:45:33 【问题描述】:

我正在使用 android 中的房间持久性库,如果有人可以帮助我使用外键,如何使用外键获取数据,我将不胜感激。

【问题讨论】:

有一个很好的Blog post关于房间的使用 与foreignKeys的关系 谢谢,这个帖子真的很好。 乐于帮助:) 创建多个 DAO 会更好,因为它会相互分离。这是SOLID Principles中的重要规则之一 medium.com/@magdamiu/… 看看这个 【参考方案1】:

只是为以后的读者总结以上帖子:

Kotlin 中的外键语法是

@Entity(foreignKeys = arrayOf(ForeignKey(entity = ParentClass::class,
                    parentColumns = arrayOf("parentClassColumn"),
                    childColumns = arrayOf("childClassColumn"),
                    onDelete = ForeignKey.CASCADE)))

Java 中的外键语法是:

@Entity(foreignKeys = @ForeignKey(entity = ParentClass.class,
    parentColumns = "parentClassColumn",
    childColumns = "childClassColumn",
    onDelete = ForeignKey.CASCADE)
)

注意:foreignKeys 是一个数组,因此在 Java 中将 @ForeignKey 元素包含在 和 中

您可以参考官方文档了解更多信息。 https://developer.android.com/reference/androidx/room/ForeignKey

【讨论】:

感谢您抽出宝贵时间实际展示并讲述。而其他人则忙于提供指向未来可能最终会发生变化的内容的链接。 很高兴能帮上忙! 谢谢,迷路了一个多小时。 Entity 内必须使用foreignKeys 还是只能使用@Relation 注释?【参考方案2】:

了解如何在 Android Jetpack Room 中定义和访问一对多 (Foreign Key) 关系。这里的实体是ArtistAlbum,外键是Album.artist

@Entity
data class Artist(
    @PrimaryKey
    val id: String,
    val name: String
)

@Entity(
    foreignKeys = [ForeignKey(
        entity = Artist::class,
        parentColumns = arrayOf("id"),
        childColumns = arrayOf("artist"),
        onDelete = ForeignKey.CASCADE
    )]
)
data class Album(
    @PrimaryKey
    val albumId: String,
    val name: String,
    @ColumnInfo(index = true)
    val artist: String
)

然后是嵌入对象 (read official Android documentation: Define relationships between objects)

data class ArtistAndAlbums(
    @Embedded
    val artist: Artist,
    @Relation(
        parentColumn = "id",
        entityColumn = "artist"
    )
    val albums: List<Album>
)

最后是DAO

@Dao
interface Library 
    @Insert
    suspend fun save(artist: Artist)

    @Insert
    suspend fun save(vararg album: Album)

    @Transaction
    @Query("SELECT * FROM artist")
    suspend fun getAll(): List<ArtistAndAlbums>

    @Transaction
    @Query("SELECT * FROM artist WHERE id = :id")
    suspend fun getByArtistId(id: String): ArtistAndAlbums

尝试一下,(所有这些操作都发生在协程中)

// creating objects
val artist = Artist(id="hillsongunited", name="Hillsong United" )
val artist2 = Artist(id="planetshakers", name="Planet Shakers" )

val album1 = Album(albumId = "empires", name = "Empires", artist = artist.id)
val album2 = Album(albumId = "wonder", name = "Wonder", artist = artist.id)
val album3 = Album(albumId = "people", name = "People", artist = artist.id)

val album4 = Album(albumId = "rain", name = "Rain", artist = artist2.id)
val album5 = Album(albumId = "itschristmas", name = "Its Christmas", artist = artist2.id)
val album6 = Album(albumId = "overitall", name = "Over It All", artist = artist2.id)

// saving to database
SongDatabase.invoke(applicationContext).library().save(artist)
SongDatabase.invoke(applicationContext).library().save(artist2)
SongDatabase.invoke(applicationContext).library().save(album1, album2, album3, album4, album5, album6)

退出所有艺术家

val all = SongDatabase.invoke(applicationContext).library().getAll()
Log.d("debug", "All Artists $all ")

D/debug: All Artists [ArtistAndAlbums(artist=Artist(id=hillsongunited, name=Hillsong United), albums=[Album(albumId=empires, name=Empires, artist=hillsongunited), Album(albumId=wonder, name=Wonder, artist=hillsongunited), Album(albumId=people, name=People, artist=hillsongunited)]), ArtistAndAlbums(artist=Artist(id=planetshakers, name=Planet Shakers), albums=[Album(albumId=rain, name=Rain, artist=planetshakers), Album(albumId=itschristmas, name=Its Christmas, artist=planetshakers), Album(albumId=overitall, name=Over It All, artist=planetshakers)])]

退出特定艺术家的专辑,

val hillsongAlbums = SongDatabase.invoke(applicationContext).library().getByArtistId(artist.id)
Log.d("debug", "Albums by artist ID: $hillsongAlbums ")

D/debug: Albums by artist ID: ArtistAndAlbums(artist=Artist(id=hillsongunited, name=Hillsong United), albums=[Album(albumId=empires, name=Empires, artist=hillsongunited), Album(albumId=wonder, name=Wonder, artist=hillsongunited), Album(albumId=people, name=People, artist=hillsongunited)]) 

【讨论】:

对于one-to-many 关系,您应该将ArtistAndAlbums 重命名为ArtistWithAlbums【参考方案3】:

@ForeignKey 注解不是在获取数据时定义关系,而是在修改时定义关系数据。要从 Room 数据库中获取关系数据,Google 建议使用 @Relation@Embedded 注释。

如果您有兴趣,可以查看my answer here 以获得更多说明。

【讨论】:

以上是关于如何在房间持久性库中使用外键的主要内容,如果未能解决你的问题,请参考以下文章

房间持久性库。删除所有

如何使主键作为房间持久性库的自动增量

如何在 Room 持久库中使用复合主键时使主键自动递增?

Android 房间持久库 - TypeConverter 错误错误:无法弄清楚如何将字段保存到数据库”

Android 房间持久性库:Upsert

房间持久性库 - 带有 List<Video> 的嵌套对象,@Embedded 不起作用。