Search code examples
androidkotlinandroid-room

Return the new rowId when a new row is added to the Room database


When I read the documentation from Android Developers, it states:

If the @Insert method receives a single parameter, it can return a long value, which is the new rowId for the inserted item.

This is exactly what I need! When a new row is inserted, I want to return the new rowId and use it in the activity. However I can't get this to work in my current setup (especially in combinations with suspend functions).

Room Entity

@Entity(
    tableName = "note_table",
    indices = [Index(
        value = ["db_key"],
        unique = true
    )]
)
data class NoteEntity(
    ...
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "db_key")
    val uid: Long? = null
)

Dao

@Dao
interface NoteEntityDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun insertNote(note: Note)
    ...
}

Repository

interface NoteRepository {

    suspend fun insertNote(note: Note)
    ...
}

Repository Implementation

class NoteRepositoryImplementation @Inject constructor(
    private val dao: NoteEntityDao
) : NoteRepository {

    override suspend fun insertNote(note: NoteEntity) {
        dao.insertNoteEntry(note)
    }

Use Case

class AddNoteUseCase(
    private val repository: NoteRepository
) {

    suspend fun execute(note: Note) {
        repository.insertNote(note)
    }
}

ViewModel

@HiltViewModel
class NoteViewModel @Inject constructor(
    private val noteUseCases: NoteUseCases
) : ViewModel() {

    fun insertNote(note: NoteEntity) {
        viewModelScope.launch {
            noteUseCases.addNoteUseCase.execute(note)
        }
    }

Activity

class NoteActivity : AppCompatActivity() {
...
val newNoteEntry = NoteEntity(
                    title = title,
                    description = description,
                    createdOn = createdOn,
                    createdBy = createdBy
                )

viewModel.insertNote(newNoteEntry)
...
}

Solution from Tenfour04:

Dao

@Dao
interface NoteEntityDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    suspend fun insertNote(note: Note): Long
    ...
}

Repository

interface NoteRepository {

    suspend fun insertNote(note: Note): Long
    ...
}

Repository Implementation

class NoteRepositoryImplementation @Inject constructor(
    private val dao: NoteEntityDao
) : NoteRepository {

    override suspend fun insertNote(note: NoteEntity): Long {
        return dao.insertNoteEntry(note)
    }
...
}

Use Case

class AddNoteUseCase(
    private val repository: NoteRepository
) {

    suspend fun execute(note: Note): Long {
        return repository.insertNote(note)
    }
}

ViewModel

@HiltViewModel
class NoteViewModel @Inject constructor(
    private val noteUseCases: NoteUseCases
) : ViewModel() {

    suspend fun insertNote(note: NoteEntity): Long {
        viewModelScope.launch {
            return noteUseCases.addNoteUseCase.execute(note)
        }
    }
...
}

Activity

class NoteActivity : AppCompatActivity() {
...
val newNoteEntry = NoteEntity(
                    title = title,
                    description = description,
                    createdOn = createdOn,
                    createdBy = createdBy
                )

lifecycleScope.launchWhenStarted {
                    val foo = viewModel.insertNote(newNoteEntry)
                    Log.d(TAG, "newRowId: $foo")
                }
...
}

Logcat Logcat output


Solution

  • In your DAO, you just need to add a Long return type to the function signature:

    suspend fun insertNote(note: Note): Long
    

    And you can add it in your repository function and so on.