Search code examples
android-roomkotlin-coroutineskotlin-flowandroid-design-libraryandroid-developer-api

Inserting data to a Room database


When it comes to inserting data on a RoomDB, what is the best method to handle the conflict strategy? As i have tried.

@Insert(onConflict = @Insert(onConflict = OnConflictStrategy.REPLACE)) 

But it didn't work, as during conflict it sometimes duplicates and mess the auto increment on the plk values.

@Insert(onConflict = OnConflictStrategy.NONE)

But that sometimes does not replace, hence at sometimes I had to go back to use the first conflict strategy @Insert(onConflict = OnConflictStrategy.REPLACE)

The documentation is giving me two statements for the same function or library @Insert(onConflict = OnConflictStrategy.REPLACE) When you whover your mouse on "REPLACE" it says "OnConflict strategy constant to replace the old data and continue the transaction" on OnConflictStrategy.REPLACE where on OnConflictStrategy.NONE you get "OnConflict strategy constant used by default when no other strategy is set. Using it prevents Room from generating ON CONFLICT clause. It may be useful when there is a need to use ON CONFLICT clause within a trigger. The runtime behavior is the same as when ABORT strategy is applied. The transaction is rolled back"

But when you navigate to the implemantation or library object. you get something like "OnConflict strategy constant to rollback the transaction." on OnConflictStrategy.REPLACE where on OnConflictStrategy.NONE you get "OnConflict strategy constant to replace the old data and continue the transaction."


Solution

  • mess the auto increment on the plk values

    The intended use of a rowid, which a column with AUTOINCREMENT is an alias of, is to uniquely identify a row. If you are using the value in another way then you may well have issues.

    The option that you appear to have dismissed is @Insert(onConflict = OnConflictStrategy.IGNORE). This will ignore the conflict and be reflected by the Long value returned by the @Insert returning -1 (instead of the generated value).

    As such if you want to do an insert or replace without the potential issues with @Insert(onConflict = OnConflictStrategy.REPLACE) then you could either

    use an @Upsert

    or use code that ignores the conflict such as :-

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    fun insert(whatever: WHATEVERCLASS): Long
    @Update
    fun update(whatever: WHATEVERCLASS): Int
    
    @Transaction
    @Query("")
    @InsertOrUpdate(whatever: WHATEVECLASS)
        if (insert(whatever) < 1) {
            update(whatever)
        }   
    }
    
    • NOTE in both circumstances reliance is made upon the primary key identifying the row to be updated.
    • if there are other constraints that result in a trappable conflict then the solution would be more complex.