Each Cast MUST have a unique id, otherwise a conflict will happen. In your case, if the same id is used, due to the use of OnConflictStrategy.REPLACE the conflict results in the cast being replaced with the data as per the new Cast.
What you should be doing to insert a new Cast, is to insert the new Cast letting the id be generated (by specifying an id of null in the case of AutoGenerate=false), retrieving the generated id e.g. using fun insertCast (cast: List <CastDbModel>): LongArray
However, with val id: Int, then you cannot specify null. So you should use var id: Int?=null (same for Movie).
Then when you want to add a Cast to a Movie, you insert a MovieCastCrossreference with the movieIdMap as the id from the respective Movie and with castIdMap as the id from the respective Cast.
With some minor changes to your code:-
@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
)
And with an @Dao annotated Interface :-
@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))
}
}
}
- note how the Inserts return a value (LongArray for inserting a List, and just Long for a single insert)
using an @Database annotated class (with .allowMainThredQueries for convenience and brevity) name TheDatabase and the following code in an activity:-
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)
}
}
The the Log Includes :-
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
- This demonstrates that you can insert with a specific id *IF THE SPECIFIC IS IS UNIQUE or with a generated id (AutoGenerate does not in fact force/stop auto generation, it just alters how to get generated id's).
To demonstrate the bonus insert an entire CastList to be related to a single Movie. The movie_cast table ends up being :-

- i.e. the 4TH (index 3) movie's id is 7655 so movieIdMap is the same for all rows
- and each castIdMap reflects the castId.