Search code examples
androidkotlinandroid-roomsql-insert

Insert Query Room OnConflictStrategy.REPLACE


I want to replace the old product list and insert new product list even if the primary key of old and new product list not same.

Interface:

@Dao
interface ProductDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertProducts(dataUser: ArrayList<Products>)

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertVariants(dataUser: Variants)
}

Product Entity:

@Entity(tableName = "Product")
data class Products (
    @PrimaryKey(autoGenerate = false)
    @ColumnInfo(name = "id")
    var id : Int = 0,

    @ColumnInfo(name = "image")
    var image: String? = null,

    @ColumnInfo(name = "other_images")
    var other_images: List<String>  = listOf(),

    @ColumnInfo(name = "variants")
    var variants : List<Variants> = listOf()
)

Variant Entity:

@Entity(tableName = "Variant",
    foreignKeys = [
    ForeignKey(
        entity = Products::class,
        parentColumns = arrayOf("id"),
        childColumns = arrayOf("product_id"),
        onDelete = ForeignKey.CASCADE
    )
])

data class Variants (
    @PrimaryKey(autoGenerate = false)
    @ColumnInfo(name = "id")
    var id : Int  = 0,

    @ColumnInfo(name = "product_id", index = true)
    var product_id : String?  = null,

    @ColumnInfo(name = "stock")
    var stock : String?  = null,

    @ColumnInfo(name = "varient_status")
    var varient_status : String?  = null,

    @ColumnInfo(name = "measurement_unit_name")
    var measurement_unit_name : String?  = null,

    @ColumnInfo(name = "stock_unit_name")
    var stock_unit_name : String?  = null,

    @ColumnInfo(name = "cart_count")
    var cart_count : String?  = null,
)

ProductWithVariants Relation:

data class ProductWithVariants(
    @Embedded val product: Products,
    @Relation(
        parentColumn = "id",
        entityColumn = "product_id"
    )
    val variants: MutableList<Variants>
)

This the area where i delete the old records in Product table and Variant table and need to add the new record into the table and need to display it in recyclerview.

ViewModel Success Response:

fun productlist() = viewModelScope.launch(Dispatchers.IO) {
    productist.collectLatest {
        when(it) {
            Resource.Empty -> {
                Log.e("catdata",""+"empty")
            }
            is Resource.Failure -> {
                Log.e("catdata",""+"failure")
            }
            Resource.Loading -> {

            }
            is Resource.Success -> {
                val response = it.value
                productsDao.deleteAllProducts()
                productsDao.insertProducts(response.data)
                for (i in 0 until response.data.size) {
                    val product: Products = response.data.get(i)
                    for (j in 0 until product.variants.size) {
                        val variants: Variants = product.variants.get(j)
                        productsDao.insertVariants(variants)
                    }
                }
            }
        }
    }
}

Main Activity where I used to call the viewmodel and get response from pagingsource using kotlin flow:

val adapter = ProductListAdapter()
binding.ProductRecyclerView.adapter = adapter.withLoadStateFooter(ProductLoadStateAdapter())

lifecycleScope.launch {
    productviewModel.data.collectLatest {
        adapter.submitData(it)
    }
}

binding.apply {
    subcatone.setOnClickListener {
        Log.e("test", "checkone")
        viewModel.getproductlist("218")
    }
    subcattwo.setOnClickListener {
        Log.e("test", "checktwo")
        viewModel.getproductlist("217")
    }
}

This is the Viewmodel to call database from MainActivity:

@HiltViewModel
class productViewModel @Inject constructor(val productsDao: ProductDao) : ViewModel() {
    val data = Pager(PagingConfig(pageSize = 20, enablePlaceholders = false, initialLoadSize = 20)) {
        ProductPagingSource(productsDao)
    }.flow.cachedIn(viewModelScope)
}

Solution

  • You need to remove old data and insert new ones again.

    @Dao
    interface ProductDao {
    
        ...
    
        
        @Query("DELETE FROM PRODUCTS")
        suspend fun deleteAllProducts()
    }
    
    

    And before inserting new items, delete old items:

    val dao = //....
    scope.launch {
        // first delete the items
        dao.deleteAllProducts()
    
        // insert new items
        dao.insertProducts(...)
    
    }