android - 无法在 Room 数据库中建立关系

标签 android sql kotlin android-room

我的 Room 数据库有问题。它由 2 个表“cast”、“movie”和一对一关系“movie_cast”组成。当我尝试构建项目时,出现以下错误:

error: Entities cannot have relations. 
public final class MovieWithCastDbModel {

error: An entity must have at least 1 field annotated with @PrimaryKey
public final class MovieWithCastDbModel {

当我从 MovieWithCastDbModel 类中删除 @Entity 注释时,我得到以下内容

error: Entity class must be annotated with @Entity
public final class MovieWithCastDbModel {

所以无论我做什么,它都会告诉我做相反的事情。

以下是数据类本身:

@Entity(tableName = "cast")
data class CastDbModel(
    @PrimaryKey(autoGenerate = false)
    var id : Int,
    var name: String,
    var profile_path: String,
    var character: String)


@Entity(tableName = "movie")
@TypeConverters(IntConverter::class)
data class MovieDbModel(
    var page: Int,
    @PrimaryKey(autoGenerate = false)
    var id: Int,
    var poster_path: String,
    var overview: String,
    var title: String,
    @ColumnInfo(name = "genre_ids")
    var genre_ids: Genres,
    var runtime: Int)


@Entity(tableName = "movie_cast")
class MovieWithCastDbModel(
    @Embedded
    var movie: MovieDbModel,
    @Relation(
        entity = CastDbModel::class,
        parentColumn = "id",
        entityColumn = "id"
    )
    var cast : CastDbModel
)


data class Genres(
    @Embedded
    var genre_ids: Int

)


class IntConverter {
    @TypeConverter
    fun fromGenres(value: Genres): String {
        return Gson().toJson(value)
    }
    @TypeConverter
    fun toGenres(value: String): Genres {
        return Gson().fromJson(value,Genres::class.java)
    }
}

可能出现什么问题?

最佳答案

正如错误消息所示。实体不能有@Relation注释。

关系实际上并不是在表中定义的(@Entity注释类),它们是独立的,除非您通过使用外键约束来强制引用完整性(子级必须有父级)来另有说明。

如果您想使用关系,那么您可以创建一个可以组合相关表数据的 POJO 类。

您拥有的是类型转换和电影表。 MovieCast 表看起来就是所谓的关联表(映射表、引用表和其他名称)。它迎合了多对多关系。也就是说,一部电影可以有许多相关的 Actor 阵容,而一个 Actor 阵容可以与许多电影相关。

所以对于 MovieWithCastDbModel 你想要类似的东西:-

@Entity(
    tableName = "movie_cast",
    primaryKeys = ["movieIdMap","castIdMap"],
    /* Optional Foreign Key constraints */
    foreignKeys = [
        /* A MovieId MUST be a value of an existing id column in the movie table */
        ForeignKey(
            entity = MovieDbModel::class,
            parentColumns = ["id"],
            childColumns = ["movieIdMap"],
            /* Optional (helps maintain referential integrity) */
            /* if parent is deleted then children rows of that parent are deleted */ 
            onDelete = ForeignKey.CASCADE,
            /* if parent column is changed then the column that references the parent is changed to the same value */
            onUpdate = ForeignKey.CASCADE
        ),
        ForeignKey(
            entity = CastDbModel::class,
            parentColumns = ["id"],
            childColumns = ["castIdMap"],
            onDelete = ForeignKey.CASCADE,
            onUpdate = ForeignKey.CASCADE
        )
    ]
)
data class MovieWithCastDbModel(
    var movieIdMap: Int,
    @ColumnInfo(index = true)
    var castIdMap: Int
)
  • 可能将其称为 MovieCast 或 MoviesCastMap 而不是 MovieWithCast 更好。

现在,为了允许提取 MoviesWithCast,您需要使用 @Embedded 作为 MovieDbModel 和一个定义关联表的 @Relation 的 POJO。

所以类似:-

data class MovieWithListOfCast(
    @Embedded /* The parent */
    var movie: MovieDbModel,
    @Relation(
        entity = CastDbModel::class, /* The class of the related table(entity) (the children)*/
        parentColumn = "id", /* The column in the @Embedded class (parent) that is referenced/mapped to */
        entityColumn = "id", /* The column in the @Relation class (child) that is referenced (many-many) or references the parent (one(parent)-many(children)) */
        /* For the mapping table */
        associateBy = Junction(
            value = MovieWithCastDbModel::class, /* The class of the mapping table */
            parentColumn = "movieIdMap", /* the column in the mapping table that maps/references the parent (@Embedded) */
            entityColumn = "castIdMap" /* the column in the mapping table that maps/references the child (@Relation) */
        )
    )
    var castList: List<CastDbModel>
)

如果您在 @Dao 注释的接口(interface)/asbtract 类中有一个函数,例如

@Transaction
@Query("SELECT * FROM movie")
fun getAllMoviesWithCastList(): List<MovieWithListOfCast>

它将检索具有相关 Actor 阵容的所有电影,作为 MovieWithListOfCast 对象列表(每部电影一个)。

Room 使用 MovieWithListOfCast 中的注释来提取所有相关的类型转换。它通过为每部电影运行底层查询来完成此操作,因此应该使用 @transaction。

关于android - 无法在 Room 数据库中建立关系,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73255805/

相关文章:

c# - 是否可以从存储过程访问 Azure Blob?

android - 没有 LifecycleOwner 引用的观察室表

java - 在非 UI 线程中做一些 Android UI 的事情

android - Flex 4.5.1 和 iOS、Android 开发

sql - SQL Server 中的 Oracle 样式日期

php - 查询生成器调用非对象上的成员函数 createQueryBuilder()

android - RecyclerView - 正确实现 SnackBar UNDO 删除 (Kotlin)

android - Room @Relation 使用复合索引

android - 在关闭应用程序之前处理最后一次后退点击的最正确方法是什么

Android 生产日志记录最佳实践