I already investigated in English I get this option android-room-persistence-library-upsert I modified it a bit and I stay like this:
@Dao
interface BloqueDao {
@Query("SELECT * FROM bloque")
suspend fun getAll(): List<bloque>
@Query("UPDATE bloque SET act=1 WHERE idfin=:finc")
suspend fun prevSetUp(finc : Int)
@Insert( onConflict = OnConflictStrategy.IGNORE)
suspend fun insertAll(vararg bloques: bloque?)
@Update
suspend fun update(vararg bloques: bloque?)
@Delete
suspend fun delete(blo: bloque)
@Transaction
suspend fun upsert(vararg bloques: bloque?) {
val insertResult = insertAll(*bloques)
if(insertResult is List<Long>){
val updateList: MutableList<bloque?> = ArrayList()
for (i in insertResult.indices)
if (insertResult[i] == -1L)
updateList.add(bloques[i])
if (updateList.isNotEmpty())
update(*updateList.toTypedArray())
}else if (insertResult == -1L)
update(bloques[0])
}
}
the problem is that kotlin tells me Incompatible types: List<Long>
and Unit. but the room library documentation says:
If the @Insert method receives only 1 parameter, it can return a long, which is the new rowId for the inserted element. If the parameter is an array or a collection, it should return long[] or List
I get this error before compiling it, if I tell it that the function insertAll returns Any
I get another error but in debugging
bug image
bug description
Cannot check for instance of erased type: List. Incompatible types: List and Unit.
SOLUTION
functions must be created separately
@Dao
interface BloqueDao {
@Query("SELECT * FROM bloque")
suspend fun getAll(): List<bloque>
@Query("UPDATE bloque SET act=1 WHERE idfin=:finc")
suspend fun prevSetUp(finc : Int)
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(bloq: bloque) : Long
@Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insertAll(bloques: List<bloque>) : List<Long>
@Update
suspend fun update(vararg bloques: bloque)
@Delete
suspend fun delete(blo: bloque)
@Transaction
suspend fun upsert(bloq: bloque) = insert(bloq).takeIf { it == -1L }.run { update(bloq) }
@Transaction
suspend fun upsert(bloques: List<bloque>) = insertAll(bloques)
.withIndex()
.filter { it.value == -1L }
.map { bloques[it.index] }
.let { if (it.isNotEmpty()) update(*it.toTypedArray()) }
}
Read the documentation carefully
The key word is " can ". This means that if you want , you can make it return a
Long
. But you defined your functioninsertAll
like thisIn Kotlin if you don't specify the return type of a function, it is considered to be
Unit
. In other words, for one to return,List<Long>
you must specify it explicitly.Although there are some things you should keep in mind. By convention, class names must start with a capital letter. That is, it should not be called
bloque
butBloque
. It also shouldn't be nullable because it doesn't work with null values. And the use ofvararg
is also not highly recommended in this case. I assume you use it for the same function to insert one or more elements but this can be confusing. It is preferable to split it atinsert
einsertAll
. This way you separate the responsibilities and get the name to correctly describe the behavior of the function.Following good practices it should look like this
But none of this is necessary because Room already has an implementation of " upsert ". You just have to use the annotation
@Insert
with the argument OnConflictStrategy.REPLACEIf you want to write your own implementation anyway, you should replace that code (which looks like an automatic conversion from Java to Kotlin) with something more idiomatic. This is exactly the same as you had but using kotlin properly