Room - update entity doesn't update value in the database

Viewed 38

I have some spinner with currency names in it. I'd like to update base currency in room db, whenever user select any of the currencies in spinner. I've wrote some functions, but it doesn't work. I've checked it in Database Inspector, and some program to read databases. The base currency remains same - the one, which I implement by default whenever database is created.

dao

@Update
fun updateBaseCurrency(baseCurrencyModel: BaseCurrencyModel)

repository

@Suppress("RedundantSuspendModifier")
@WorkerThread
suspend fun updateBaseCurrency(baseCurrencyModel: BaseCurrencyModel){
    currencyDAO.updateBaseCurrency(baseCurrencyModel)
}

view model

fun updateCurrency(baseCurrencyModel: BaseCurrencyModel) {
    viewModelScope.launch(Dispatchers.IO) {
        currencyDatabaseRepository.updateBaseCurrency(baseCurrencyModel)
    }
}

model class

    @Entity(tableName = "base_currency")
data class BaseCurrencyModel(
    @PrimaryKey
    @ColumnInfo(name = "base_curr")
    val baseCurrency: String


) {
    override fun toString(): String {
        return this.baseCurrency
    }
}

on click listener from spinner

private fun prepareSpinner(list: List<CurrencyNamesModel>) {
    val spinnerAdapter = ArrayAdapter(
        requireActivity(), android.R.layout.simple_spinner_item, list
    )
    mSelectNewBaseCurrency?.adapter = spinnerAdapter
    mSelectNewBaseCurrency?.setSelection(0, false)
    mSelectNewBaseCurrency?.onItemSelectedListener =
        object : AdapterView.OnItemSelectedListener, AdapterView.OnItemClickListener {
            override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
                Log.i(TAG, "onItemSelected: "+mAllCurrencyNames[p2])
                updateBaseCurrency(mAllCurrencyNames[p2].toString())
            }

            override fun onNothingSelected(p0: AdapterView<*>?) {
                Log.i(TAG, "onNothingSelected: ")
            }

...

updateBaseCurrency

 private fun updateBaseCurrency(selectedCurrency: String) {
    val newBase = BaseCurrencyModel(selectedCurrency)
    Log.i(TAG, "updateBaseCurrency: $selectedCurrency || $newBase")

    CoroutineScope(Dispatchers.IO).launch {
        mDatabaseViewModel.updateCurrency(newBase)
    }
}

logs

I/ChangeBaseCurrency: onItemSelected: AZN 
I/ChangeBaseCurrency: updateBaseCurrency: AZN || AZN
1 Answers

I'd like to update base currency in room db.

According to I/ChangeBaseCurrency: updateBaseCurrency: AZN || AZN and in conjection with the BaseCurrrencyModel then you are saying that you want to change AZN to AZN as there is just the one column and that it is the primary key.

  • The @Update will change the respective row that is determined by the primary key to the values on off the fields/columns (except those considered to not be columns in the table such as any that have the @Ignore annotation). IT CANNOT CHANGE THE PRIMARY KEY

To change the primary key you would have to use an @Query that uses an update statement. For what I believe is your situation (just one row for the currently selected base currency which can be changed according to a list elsewhere)

e.g. if you had:-

@Query("UPDATE OR IGNORE base_currency SET base_curr=:new_base_curr")
fun updBaseCurrency(new_base_curr): Int
  • note this will only ever change 1 row as the base_curr is the primary key, which is implicitly unique. However, as note this would work for just the 1 row.

  • Room's convenience method is effectively doing the equivalent of @Query("UPDATE OR IGNORE base_currency SET base_curr=:base_curr") (which will do nothing other than waste time)

Another potential scenario

If you had a list of currencies and 1 should indicate that it is the base currency then you could have an additional field e.g.

@Entity(tableName = "base_currency")
data class BaseCurrencyModel(
    @PrimaryKey
    @ColumnInfo(name = "base_curr")
    val baseCurrency: String
    val baseCurrencyIndicator: Boolean = false


) {
    override fun toString(): String {
        return this.baseCurrency
    }
}

You could then have a function to set the baseCurrency which could be:-

@Query("UPDATE base_currency SET baseCurrencyIndicator=(base_curr=:new_base_curr) WHERE :new_base_curr IN (SELECT base_curr FROM base_currency )"
  • This works as it is updating every row to change the indicator to be whether (true aka 1 (or more correctly not 0)) or not (false aka 0) the currency matches the passed currency.
  • The where clause is used to ensure that nothing is updated if the new base currency (passed as new_base_curr) does not exist in the table.
Related