Search code examples
androidkotlinandroid-room

AutoIncrement of Room Entity Id is not working


My app is currently using retrofit and Room but I am struggling to find a way to autogenerate the id of the Db object. When mapping retrofit object to the RoomDb entity, it keeps asking for an id to filed up even if I added the autogenerate key

Below is the retrofit object:

data class RetrofitProduct(
    @SerializedName("id")
    val id: String,
    @SerializedName("types")
    val types: List<String>,
    @SerializedName("date")
    val date: String,
)

and the associated Room Entity:

@Entity
data class ProductEntity(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id")
    val id: Int,
    @ColumnInfo(name = "productId")
    val productId: String,
    @ColumnInfo(name = "types")
    val types: List<String>,
)

the Mapper is as below:

fun RetrofitProduct.toEntity(): ProductEntity {
    return ProductEntity(
        productId = this.id,
        types = this.types,
    )
}

But at build time, the compiler complains that I need to add the id:

No value passed for parameter 'id'

I want this id to be generated by Room as a way to get the number of items for my paging.

Basically if I pull the lastItem, I know that with the id is for example: 25. So I need to ask for 26 and more.


Solution

  • This is actually a pretty common gotcha when working with Room and auto-generated IDs. The problem is that even though you've marked the ID as autoGenerate = true, Kotlin still requires all parameters to be provided in the constructor since ProductEntity is a data class. Here are a couple of ways to solve this:

    The quickest fix - provide a default value of 0:

    kotlinCopy@Entity
    data class ProductEntity(
        @PrimaryKey(autoGenerate = true)
        @ColumnInfo(name = "id")
        val id: Int = 0,  // Add this default value
        @ColumnInfo(name = "productId")
        val productId: String,
        @ColumnInfo(name = "types")
        val types: List<String>,
    )
    

    Or if you prefer being more explicit in your mapper:

    kotlinCopyfun RetrofitProduct.toEntity(): ProductEntity {
        return ProductEntity(
            id = 0,  // Room will ignore this and auto-generate
            productId = this.id,
            types = this.types,
        )
    }
    

    Room will ignore the 0 value and auto-generate a new ID when you insert the entity. This works because Room checks for 0 or null (depending on if you're using nullable types) as signals to auto-generate the ID. When you use this approach for paging, you can still query the last item's ID just fine since Room will have replaced that 0 with the actual auto-generated value.