sqlite 聊天室数据库重写具有相同ID的值

7cjasjjr  于 2022-11-15  发布在  SQLite
关注(0)|答案(1)|浏览(149)

我使用房间数据库(多对多关系)。我试着把演员名单保存到一个表中。但是数据库发现我插入了具有相同id(电影id)的cast,并重写了该值。你知道怎么改正吗?
我在以下查询的帮助下插入一个列表:

@Insert(onConflict = OnConflictStrategy.REPLACE)
   suspend fun insertCast (cast: List <CastDbModel>)

但当我尝试获取数据时,我得到了插入的最后一个数据。

@Transaction
   @Query("select * FROM `cast` WHERE id = :id")
   fun getAllCastAssociatedWithMovie(id: Int): List<CastDbModel>

@Entity(tableName = "movie")
data class MovieDbModel(
   @PrimaryKey(autoGenerate = false)
   val id: Int,
   val poster_path: String,
   val overview: String,
   val title: String)

@Entity(tableName = "cast")
@TypeConverters(CastConverter::class)
data class CastDbModel(
   @PrimaryKey(autoGenerate = false)
   val id : Int,
   val cast: Cast
)

data class Cast(
   val name: String,
   val profile_path: String?,
   val character: String
)
data class MovieWithListOfCast(
   @Embedded /* The parent */
   val movie: CastDbModel,
   @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 = MovieCastCrossRef::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) */
       )
   )
   val castList: List<CastDbModel>
)

@Entity(
   tableName = "movie_cast",
   primaryKeys = ["movieIdMap","castIdMap"],
   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 MovieCastCrossRef(
   val movieIdMap: Int,
   @ColumnInfo(index = true)
   val castIdMap: Int
)
6yjfywim

6yjfywim1#

每个cast必须有唯一的id,否则会发生冲突。在您的例子中,如果使用相同的id,则由于使用OnConflictStrategy.REPLACE,冲突会导致根据新的强制转换用数据替换强制转换。
要插入新的强制转换,应该插入允许生成id的新强制转换(在AutoGenerate=False的情况下,通过将id指定为空),检索生成的id,例如使用fun insertCast (cast: List <CastDbModel>): LongArray
但是,对于val id: Int,,您不能指定NULL。因此,您应该使用var id:int?=NULL(与Movie相同)。
然后,当您想要向Movie中添加一个演员时,您可以插入一个MovieCastCrossReference,其MovieIdMap作为来自相应Movie的id,CastIdMap作为来自各个演员的id。
对您的代码进行一些细微的更改:

@Entity(tableName = "movie")
data class MovieDbModel(
    @PrimaryKey(autoGenerate = false)
    var id: Int?=null, /*<<<<<<<<<< CHANGED to var and default value of null so id can be generated */
    val poster_path: String,
    val overview: String,
    val title: String)

@Entity(tableName = "cast")
@TypeConverters(CastConverter::class)
data class CastDbModel(
    @PrimaryKey(autoGenerate = false)
    var id : Int?=null, /*<<<<<<<<<< CHANGED to var and default value of null so id can be generated */
    val cast: Cast
)

并使用@DAO注解的接口:-

@Dao
interface AllDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun insertMovie(movie: List<MovieDbModel>): LongArray
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun insertCast (cast: List <CastDbModel>): LongArray
    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun insertMovieCastXrossRef(movieCastCrossRef: MovieCastCrossRef): Long

    @Transaction
    @Query("") /* Allows the function to have the @Transaction Applied */
    fun insertCastListForASingleMovie(movieId: Int, castList: List<Int>) {
        for (castId in castList) {
            insertMovieCastXrossRef(MovieCastCrossRef(movieId,castId))
        }
    }
}
  • 注意插入是如何返回值的(用于插入列表的Long数组,并且只需要单个插入)

在活动中使用@数据库注解类(为方便和简洁起见,使用.AllowMainThredQueries)命名数据库和以下代码:-

class MainActivity : AppCompatActivity() {
    lateinit var db: TheDatabase
    lateinit var dao: AllDao
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        db = TheDatabase.getInstance(this)
        dao = db.getAllDao()

        /* Define some Movies */
        val movieList = listOf<MovieDbModel>(
            MovieDbModel(null,"p1","blah1","M1"), /* when run first odds on id will be 1 */
            MovieDbModel(null,"p2","blah2","M2"), /* id likely 2 */
            MovieDbModel(7654,"p3","blah3","M3"), /* id as given i.e 7654 */
            MovieDbModel(null,"p4","blah4","M4"), /* id likely 7655 */
            /* Will very likely NOT BE INSERTED as Movie with id 1 will likely exist */
            MovieDbModel(1,"pOoops","blahOoops","MOoops")
        )
        /* Insert the Movies setting the movieId accordingly from the returned list of inserted id's
            noting that if an insert failed (was ignored i.e. returned id is -1) then a different Log message
         */
        var movieIndex = 0
        for (movieId in dao.insertMovie(movieList)) {
            if (movieId > 0) {
                Log.d("MOVIEINSERT","Movie ${movieList[movieIndex].title} was inserted with an ID of $movieId")

            } else {
                Log.d("MOVIEINSERT","Movie ${movieList[movieIndex].title} insert FAILED due to CONFLICT")
            }
            movieList[movieIndex++].id = movieId.toInt()
        }

        /* Define some CastDBModels */
        val castList = listOf<CastDbModel>(
            CastDbModel(null,Cast("Fred","fredprofile","fred is fred")),
            CastDbModel(null,Cast("Mary","maryprofile","mary is mary")),
            CastDbModel(null, Cast("Anne","anneprofile","anne is anne")),
            CastDbModel(50124,Cast("Tom","tomprofile","tom is tom")),
            CastDbModel(null,Cast("Bert","bertprofile","bert is bert")),
            CastDbModel(null,Cast("Jane","janeprofile","jane is jane")),
            /* Will very likely NOT BE INSERTED as Movie with id 1 will likely exist */
            CastDbModel(1,Cast("Oooops","NOPROFILE","NOCHARACTER"))
        )
        /* Similar to movies */
        val castIdList = dao.insertCast(castList)
        var castIndex = 0
        val castListToUse: ArrayList<Int> = ArrayList()
        for (castId in castIdList) {
            if (castId > 0) {
                Log.d("CASTINSERT","Cast ${castList[castIndex].cast.name} was inserted with an ID of $castId")
                castList[castIndex].id = castId.toInt()
                castListToUse.add(castId.toInt())
            } else {
                Log.d("CASTINSERT","Cast ${castList[castIndex].cast.name} insert Failed")
            }
            castIndex++
        }
        /* Add all the inserted Casts to the 3rd Movie */
        dao.insertCastListForASingleMovie(movieList[3].id!!,castListToUse)
    }
}

日志包括:-

2022-09-09 11:21:52.778 D/MOVIEINSERT: Movie M1 was inserted with an ID of 1
2022-09-09 11:21:52.778 D/MOVIEINSERT: Movie M2 was inserted with an ID of 2
2022-09-09 11:21:52.778 D/MOVIEINSERT: Movie M3 was inserted with an ID of 7654
2022-09-09 11:21:52.778 D/MOVIEINSERT: Movie M4 was inserted with an ID of 7655
2022-09-09 11:21:52.778 D/MOVIEINSERT: Movie MOoops insert FAILED due to CONFLICT

2022-09-09 11:21:52.832 D/CASTINSERT: Cast Fred was inserted with an ID of 1
2022-09-09 11:21:52.833 D/CASTINSERT: Cast Mary was inserted with an ID of 2
2022-09-09 11:21:52.833 D/CASTINSERT: Cast Anne was inserted with an ID of 3
2022-09-09 11:21:52.833 D/CASTINSERT: Cast Tom was inserted with an ID of 50124
2022-09-09 11:21:52.833 D/CASTINSERT: Cast Bert was inserted with an ID of 50125
2022-09-09 11:21:52.833 D/CASTINSERT: Cast Jane was inserted with an ID of 50126
2022-09-09 11:21:52.833 D/CASTINSERT: Cast Oooops insert Failed
  • 这说明您可以使用特定的id插入**如果特定的is是唯一的*或使用生成的id(AutoGenerate实际上不强制/停止自动生成,它只是改变了获取生成的id的方式)。

为了演示奖金,插入与单个电影相关的整个演员列表。MOVICE_CAST表最终为:-

  • 即第4部(索引3)电影的ID为7655,因此MovieIdMap对所有行都相同
  • 每个CastIdMap都反映了CastID。

相关问题