androidforeign-keysandroid-roomrdbmscascade

Android: why Room removes parent if I remove only child?


I'm working with Room for an android application.

@Entity(tableName = "author")
data class AuthorEntity(
@PrimaryKey
@ColumnInfo(name = "authorId")
val authorId: String,
@ColumnInfo(name = "name")
val name: String?

@Entity(tableName = "book")
data class BookEntity(
@PrimaryKey
@ColumnInfo(name = "bookId")
val bookId: String,
@ColumnInfo(name = "title")
val title: String?

@Entity(
    tableName = "author_book",
    primaryKeys = ["authorId", "bookId"],
    foreignKeys = [
        ForeignKey(
            entity = AuthorEntity::class,
            parentColumns = arrayOf("authorId"),
            childColumns = arrayOf("authorId"),
            onDelete = ForeignKey.CASCADE,
            onUpdate = ForeignKey.CASCADE
        ),
        ForeignKey(
            entity = BookEntity::class,
            parentColumns = arrayOf("bookId"),
            childColumns = arrayOf("bookId"),
            onDelete = ForeignKey.CASCADE,
            onUpdate = ForeignKey.CASCADE
        )
    ]
)
data class AuthorBookCrossRef(
    val authorId: String,
    val bookId: String,
    val desc: String
)

data class NewsWithSectionWithContract(
    @Embedded val authorEntity: AuthorEntity,
    @Relation(
        parentColumn = "authorId",
        entityColumn = "bookId",
        associateBy = Junction(
            AuthorBookCrossRef::class
        )
    )
    var bookEntities: List<BookEntity>
)

If I remove BookEntity it should remove only AuthorBookCrossRef row, so why does it also remove AuthorEntity?


Solution

  • I believe that you are mistaken or not checking the actual data.

    Using the code you have provided and additionally:-

    @Dao
    interface AllDAOs{
        @Insert(onConflict = OnConflictStrategy.IGNORE)
        fun insert(authorEntity: AuthorEntity): Long
        @Insert(onConflict = OnConflictStrategy.IGNORE)
        fun insert(bookEntity: BookEntity): Long
        @Insert(onConflict = OnConflictStrategy.IGNORE)
        fun insert(authorBookCrossRef: AuthorBookCrossRef): Long
    
        @Delete
        fun delete(authorBookCrossRef: AuthorBookCrossRef): Int
        @Delete
        fun delete(bookEntity: BookEntity): Int
        @Delete
        fun delete(authorEntity: AuthorEntity): Int
    
        @Query("SELECT * FROM author")
        fun getAllAuthors(): List<AuthorEntity>
        @Query("SELECT * FROM book")
        fun getAllBooks(): List<BookEntity>
        @Query("SELECT* FROM author_book")
        fun getAllAuthorBookRefs(): List<AuthorBookCrossRef>
        @Transaction
        @Query("SELECT * FROM author")
        fun getAllAuthorsWithBooks(): List<NewsWithSectionWithContract>
    }
    
    @Database(entities = [AuthorEntity::class,BookEntity::class,AuthorBookCrossRef::class], version = 1, exportSchema = false)
    abstract class TheDatabase: RoomDatabase() {
        abstract fun getAllDAOs(): AllDAOs
    
        companion object {
            var instance: TheDatabase?=null
            fun getInstance(context: Context): TheDatabase {
                if (instance==null) {
                    instance = Room.databaseBuilder(context,TheDatabase::class.java,"the_database.db")
                        .allowMainThreadQueries()
                        .build()
                }
                return instance as TheDatabase
            }
        }
    }
    

    And then in an activity:-

    class MainActivity : AppCompatActivity() {
        lateinit var db: TheDatabase
        lateinit var dao: AllDAOs
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            db = TheDatabase.getInstance(this)
            dao = db.getAllDAOs()
    
            dao.insert(AuthorEntity("LC001","Lewis Carrol"))
            dao.insert(AuthorEntity("JS001","John Steinbeck"))
            dao.insert(AuthorEntity("WS001","William Shakespeare"))
            dao.insert(AuthorEntity("CD001","Charles Dickens"))
    
            dao.insert(BookEntity("b001","David Copperfield"))
            dao.insert(BookEntity("b002","Oliver"))
            dao.insert(BookEntity("b003","Alice in Wonderland"))
            dao.insert(BookEntity("b004","Alice through the Looking Glass"))
            dao.insert(BookEntity("b005","The Lion, the Witch and the Wardrobe"))
            dao.insert(BookEntity("b006","Wrath of the grapes"))
            dao.insert(BookEntity("b007","Day of the Triffids"))
            dao.insert(BookEntity("b008","Something"))
    
            dao.insert(AuthorBookCrossRef("LC001","b003","AIW"))
            dao.insert(AuthorBookCrossRef("LC001","b004","ATTLG"))
            dao.insert(AuthorBookCrossRef("JS001","b007","DOTT"))
            dao.insert(AuthorBookCrossRef("JS001","b006","WOTG"))
            dao.insert(AuthorBookCrossRef("CD001","b001","DC"))
            dao.insert(AuthorBookCrossRef("CD001","b002","O"))
    
            logAllData("_STAGE1")
    
            dao.delete(BookEntity("b004","does not matter!!!!"))
    
            logAllData("_STAGE2")
    
        }
    
        fun logAllData(tagSuffix: String) {
            val tag = "DBINFO_"
            Log.d(tag + tagSuffix,"ALL Authors")
            for (a in dao.getAllAuthors()) {
                Log.d(tag + tagSuffix,"\tAuthor is ${a.name} ID is ${a.authorId}")
            }
            Log.d(tag + tagSuffix,"ALL Books")
            for (b in dao.getAllBooks()) {
                Log.d(tag + tagSuffix,"\tBook is ${b.title} ID is ${b.bookId}")
            }
            Log.d(tag + tagSuffix,"All Author Book Refs")
            for (ab in dao.getAllAuthorBookRefs()) {
                Log.d(tag + tagSuffix,"\t AID is ${ab.authorId} BID is ${ab.bookId} DESC is ${ab.desc}")
            }
            Log.d(tag + tagSuffix,"Authors with Books")
            for (awb in dao.getAllAuthorsWithBooks()) {
                val sb=StringBuilder()
                for (b in awb.bookEntities) {
                    sb.append("\n\t\tBook is ${b.title} BID is ${b.bookId}")
                }
                Log.d(tag + tagSuffix,"Author is ${awb.authorEntity.name}. Has ${awb.bookEntities.size} Books. They are:$sb" )
            }
        }
    }
    

    Then it can be seen that deleting the book with an id of "b004" does not remove the author.

    That is prior to the deletion the output from the log is:-

    2023-05-18 06:57:57.556 D/DBINFO__STAGE1: ALL Authors
    2023-05-18 06:57:57.563 D/DBINFO__STAGE1:   Author is Lewis Carrol ID is LC001
    2023-05-18 06:57:57.563 D/DBINFO__STAGE1:   Author is John Steinbeck ID is JS001
    2023-05-18 06:57:57.563 D/DBINFO__STAGE1:   Author is William Shakespeare ID is WS001
    2023-05-18 06:57:57.564 D/DBINFO__STAGE1:   Author is Charles Dickens ID is CD001
    2023-05-18 06:57:57.564 D/DBINFO__STAGE1: ALL Books
    2023-05-18 06:57:57.565 D/DBINFO__STAGE1:   Book is David Copperfield ID is b001
    2023-05-18 06:57:57.565 D/DBINFO__STAGE1:   Book is Oliver ID is b002
    2023-05-18 06:57:57.565 D/DBINFO__STAGE1:   Book is Alice in Wonderland ID is b003
    2023-05-18 06:57:57.565 D/DBINFO__STAGE1:   Book is Alice through the Looking Glass ID is b004
    2023-05-18 06:57:57.565 D/DBINFO__STAGE1:   Book is The Lion, the Witch and the Wardrobe ID is b005
    2023-05-18 06:57:57.565 D/DBINFO__STAGE1:   Book is Wrath of the grapes ID is b006
    2023-05-18 06:57:57.565 D/DBINFO__STAGE1:   Book is Day of the Triffids ID is b007
    2023-05-18 06:57:57.565 D/DBINFO__STAGE1:   Book is Something ID is b008
    2023-05-18 06:57:57.565 D/DBINFO__STAGE1: All Author Book Refs
    2023-05-18 06:57:57.566 D/DBINFO__STAGE1:    AID is LC001 BID is b003 DESC is AIW
    2023-05-18 06:57:57.566 D/DBINFO__STAGE1:    AID is LC001 BID is b004 DESC is ATTLG
    2023-05-18 06:57:57.566 D/DBINFO__STAGE1:    AID is JS001 BID is b007 DESC is DOTT
    2023-05-18 06:57:57.566 D/DBINFO__STAGE1:    AID is JS001 BID is b006 DESC is WOTG
    2023-05-18 06:57:57.566 D/DBINFO__STAGE1:    AID is CD001 BID is b001 DESC is DC
    2023-05-18 06:57:57.566 D/DBINFO__STAGE1:    AID is CD001 BID is b002 DESC is O
    2023-05-18 06:57:57.566 D/DBINFO__STAGE1: Authors with Books
    2023-05-18 06:57:57.575 D/DBINFO__STAGE1: Author is Lewis Carrol. Has 2 Books. They are:
                Book is Alice in Wonderland BID is b003
                Book is Alice through the Looking Glass BID is b004
    2023-05-18 06:57:57.575 D/DBINFO__STAGE1: Author is John Steinbeck. Has 2 Books. They are:
                Book is Wrath of the grapes BID is b006
                Book is Day of the Triffids BID is b007
    2023-05-18 06:57:57.575 D/DBINFO__STAGE1: Author is William Shakespeare. Has 0 Books. They are:
    2023-05-18 06:57:57.575 D/DBINFO__STAGE1: Author is Charles Dickens. Has 2 Books. They are:
                Book is David Copperfield BID is b001
                Book is Oliver BID is b002
    

    Whilst after the deletion of book b004 then:-

    2023-05-18 06:57:57.577 D/DBINFO__STAGE2: ALL Authors
    2023-05-18 06:57:57.579 D/DBINFO__STAGE2:   Author is Lewis Carrol ID is LC001
    2023-05-18 06:57:57.579 D/DBINFO__STAGE2:   Author is John Steinbeck ID is JS001
    2023-05-18 06:57:57.579 D/DBINFO__STAGE2:   Author is William Shakespeare ID is WS001
    2023-05-18 06:57:57.580 D/DBINFO__STAGE2:   Author is Charles Dickens ID is CD001
    2023-05-18 06:57:57.580 D/DBINFO__STAGE2: ALL Books
    2023-05-18 06:57:57.583 D/DBINFO__STAGE2:   Book is David Copperfield ID is b001
    2023-05-18 06:57:57.583 D/DBINFO__STAGE2:   Book is Oliver ID is b002
    2023-05-18 06:57:57.583 D/DBINFO__STAGE2:   Book is Alice in Wonderland ID is b003
    2023-05-18 06:57:57.583 D/DBINFO__STAGE2:   Book is The Lion, the Witch and the Wardrobe ID is b005
    2023-05-18 06:57:57.583 D/DBINFO__STAGE2:   Book is Wrath of the grapes ID is b006
    2023-05-18 06:57:57.583 D/DBINFO__STAGE2:   Book is Day of the Triffids ID is b007
    2023-05-18 06:57:57.583 D/DBINFO__STAGE2:   Book is Something ID is b008
    2023-05-18 06:57:57.583 D/DBINFO__STAGE2: All Author Book Refs
    2023-05-18 06:57:57.585 D/DBINFO__STAGE2:    AID is LC001 BID is b003 DESC is AIW
    2023-05-18 06:57:57.585 D/DBINFO__STAGE2:    AID is JS001 BID is b007 DESC is DOTT
    2023-05-18 06:57:57.585 D/DBINFO__STAGE2:    AID is JS001 BID is b006 DESC is WOTG
    2023-05-18 06:57:57.585 D/DBINFO__STAGE2:    AID is CD001 BID is b001 DESC is DC
    2023-05-18 06:57:57.585 D/DBINFO__STAGE2:    AID is CD001 BID is b002 DESC is O
    2023-05-18 06:57:57.586 D/DBINFO__STAGE2: Authors with Books
    2023-05-18 06:57:57.604 D/DBINFO__STAGE2: Author is Lewis Carrol. Has 1 Books. They are:
                Book is Alice in Wonderland BID is b003
    2023-05-18 06:57:57.604 D/DBINFO__STAGE2: Author is John Steinbeck. Has 2 Books. They are:
                Book is Wrath of the grapes BID is b006
                Book is Day of the Triffids BID is b007
    2023-05-18 06:57:57.604 D/DBINFO__STAGE2: Author is William Shakespeare. Has 0 Books. They are:
    2023-05-18 06:57:57.604 D/DBINFO__STAGE2: Author is Charles Dickens. Has 2 Books. They are:
                Book is David Copperfield BID is b001
                Book is Oliver BID is b002
    

    i.e. Lewis Carrol still exists even though Alice through the Looking Glass has been deleted (noting that the incorrect title has been ignored i.e. the deletion is based upon the primary key value).

    If the last book "b003" is then deleted then :-

    2023-05-18 07:15:00.320 D/DBINFO__STAGE2: ALL Authors
    2023-05-18 07:15:00.323 D/DBINFO__STAGE2:   Author is Lewis Carrol ID is LC001
    2023-05-18 07:15:00.323 D/DBINFO__STAGE2:   Author is John Steinbeck ID is JS001
    2023-05-18 07:15:00.323 D/DBINFO__STAGE2:   Author is William Shakespeare ID is WS001
    2023-05-18 07:15:00.323 D/DBINFO__STAGE2:   Author is Charles Dickens ID is CD001
    2023-05-18 07:15:00.323 D/DBINFO__STAGE2: ALL Books
    2023-05-18 07:15:00.326 D/DBINFO__STAGE2:   Book is David Copperfield ID is b001
    2023-05-18 07:15:00.326 D/DBINFO__STAGE2:   Book is Oliver ID is b002
    2023-05-18 07:15:00.326 D/DBINFO__STAGE2:   Book is The Lion, the Witch and the Wardrobe ID is b005
    2023-05-18 07:15:00.326 D/DBINFO__STAGE2:   Book is Wrath of the grapes ID is b006
    2023-05-18 07:15:00.326 D/DBINFO__STAGE2:   Book is Day of the Triffids ID is b007
    2023-05-18 07:15:00.326 D/DBINFO__STAGE2:   Book is Something ID is b008
    2023-05-18 07:15:00.326 D/DBINFO__STAGE2: All Author Book Refs
    2023-05-18 07:15:00.329 D/DBINFO__STAGE2:    AID is JS001 BID is b007 DESC is DOTT
    2023-05-18 07:15:00.329 D/DBINFO__STAGE2:    AID is JS001 BID is b006 DESC is WOTG
    2023-05-18 07:15:00.329 D/DBINFO__STAGE2:    AID is CD001 BID is b001 DESC is DC
    2023-05-18 07:15:00.329 D/DBINFO__STAGE2:    AID is CD001 BID is b002 DESC is O
    2023-05-18 07:15:00.329 D/DBINFO__STAGE2: Authors with Books
    2023-05-18 07:15:00.334 D/DBINFO__STAGE2: Author is Lewis Carrol. Has 0 Books. They are:
    2023-05-18 07:15:00.334 D/DBINFO__STAGE2: Author is John Steinbeck. Has 2 Books. They are:
                Book is Wrath of the grapes BID is b006
                Book is Day of the Triffids BID is b007
    2023-05-18 07:15:00.334 D/DBINFO__STAGE2: Author is William Shakespeare. Has 0 Books. They are:
    2023-05-18 07:15:00.334 D/DBINFO__STAGE2: Author is Charles Dickens. Has 2 Books. They are:
                Book is David Copperfield BID is b001
                Book is Oliver BID is b002
    

    i.e. Lewis Carrol still exists, however he has 0 books.