androidkotlinandroid-room

Room Can not Update or Delete Entity


I'm learning how to use the room framework, but I can't update or delete entity in androidTest. Here is my code:

@Database(entities = [Note::class], version = 1)
@TypeConverters(com.misaka.workflow.data.local.TypeConverter::class)
abstract class SQLiteDataBase : RoomDatabase() {

    abstract fun getNoteDAO(): NoteDAO

    companion object {
        @Volatile
        private var INSTANCE: SQLiteDataBase? = null

        fun getInstance (context: Context): SQLiteDataBase {
            return INSTANCE ?: synchronized(this) {
                INSTANCE ?: Room.databaseBuilder(
                    context.applicationContext,
                    SQLiteDataBase::class.java,
                    "WorkFlow"
                ).build().also { INSTANCE = it }
            }
        }
    }
}

@Dao
interface NoteDAO {

    @Query("select * from note")
    fun getAllNote(): List<Note>

    @Delete
    fun deleteNotes(vararg notes: Note): Int

    @Insert
    fun insertNewNotes(vararg node: Note)

    @Update(onConflict = OnConflictStrategy.REPLACE)
    fun updateNote(note: Note): Int

    @Query("select * from note")
    fun getAllNoteInFlow(): Flow<List<Note>>

    @Query("delete from note where id = :id")
    fun test(id: Int)

    @Query("update note set title = :title where id = :id")
    fun test2(id: Int, title: String)
}

@Entity(
    tableName = "note"
)
data class Note(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,

    @ColumnInfo(name = "title")
    val title: String = "",

    @ColumnInfo(name = "noteContent")
    val content: String = "",

    @ColumnInfo(name = "modifyTime")
    val modifyTime: LocalDateTime = LocalDateTime.now()
)

class NoteUnitTest {
    private lateinit var repository: NoteRepository

    private lateinit var database: SQLiteDataBase
    private lateinit var dao: NoteDAO

    @Before
    fun setup() {
        database = Room.inMemoryDatabaseBuilder(
            ApplicationProvider.getApplicationContext(),
            SQLiteDataBase::class.java
        ).build()

        dao = database.getNoteDAO()

        repository = NoteRepository(dao)
    }

    @After
    fun close() {
        database.close()
    }

    @Test
    fun testDAO() = runTest {
        try {
            val noteFlow = dao.getAllNoteInFlow()

            val note = Note(title = "test", content = "testContent", modifyTime = LocalDateTime.now())

            dao.insertNewNotes(note)

            launch {
                noteFlow.collect { value ->
                    println(value)
                }
            }

            val newNote = note.copy(title = "test1", id = note.id)
            dao.test2(newNote.id, newNote.title)
            dao.updateNote(newNote)

            dao.deleteNotes(newNote)
        } catch (e: Exception) {
            println(e.stackTrace)
        }
    }
}

After running the test, I only get one value from the Flow, which is the entity I inserted at the beginning. I don't understand what the problem is. I would be very grateful if anyone could help me.


Solution

  • You can't update/delete your entities because of the ids. You are declaring id like this val id: Int = 0 but ids in database starts with 1. Inserting Note instance will not update id of the instance. Id of note in your code is still 0 and when you are trying to update/delete them, database simply can't find them.

    As mentioned here, you cant return Long for single insert operation containing number of inserted row (id), so you can e.g. set Id value on insert like this:

    Change id from val to var and type from Int to Long:

    @Entity(
        tableName = "note"
    )
    data class Note(
        @PrimaryKey(autoGenerate = true)
        var id: Long = 0,
    
        @ColumnInfo(name = "title")
        val title: String = "",
    
        @ColumnInfo(name = "noteContent")
        val content: String = "",
    )
    

    Inside NoteDao add insert for one note returning Long:

    @Insert
    fun insertNewNote(node: Note): Long
    

    Then you can set note id while inserting it:

    val note = Note(title = "test", content = "testContent")
    note.id = dao.insertNewNote(note)
    

    After these changes you will be able to update, delete notes and also see logs from noteFlow collection.