androidandroid-roomandroid-room-relationandroid-room-embedded

Room entity on @Embedded annotation has id always 0


I am struggling with executing queries containing JOIN in room. The problem is, that in the entity joining multiple entities I get the @Embedded entity with ID of always 0.

This are my following entities:

@Entity(
    tableName = "FinancialCategories",
    indices = [Index(value = ["name"], unique = true)]
)
data class FinancialCategory(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id")
    val id: Long = 0L,

    @ColumnInfo(name = "name")
    val name: String,

    @ColumnInfo(name = "parent")
    val parent: Long
)
@Entity(
    tableName = "FinancialRecords",
    foreignKeys = [ForeignKey(
        entity = FinancialCategory::class,
        parentColumns = ["id"],
        childColumns = ["category"],
        onDelete = ForeignKey.CASCADE
    )],
    indices = [Index(value = ["title"], unique = true), Index(value = ["category"], unique = false)]
)
data class FinancialRecord(
    @PrimaryKey(autoGenerate = true)
    val id: Long = 0L,

    @ColumnInfo(name = "title")
    val title: String,

    @ColumnInfo(name = "amount")
    val amount: BigDecimal,

    @ColumnInfo(name = "category")
    val category: Long
)

This is the relation entity:

data class CategoryWithRecords(
    @Embedded
    val category: FinancialCategory,

    @Relation(
        parentColumn = "id",
        entityColumn = "category"
    )
    val records: List<FinancialRecord>
)

And this is how I fetch this data from room:

    @Transaction
    @Query("SELECT *" +
           "FROM FinancialCategories " + 
           "LEFT JOIN FinancialRecords " +
           "ON FinancialCategories.id = FinancialRecords.category " +
           "WHERE FinancialCategories.parent = (SELECT id FROM FinancialCategories WHERE name = :categoryName);")
    fun getCategoriesWithItems(categoryName: String): Flow<List<CategoryWithRecords>>

And this is my repository:

fun getFinancialData(category: FinancialCategories): Flow<Map<FinancialCategory, List<FinancialRecord>>> {
        return categoryDao.getCategoriesWithItems(category.displayName).map {
            it.associate {
                    categoryWithRecords -> categoryWithRecords.category to categoryWithRecords.records
            }
        }
    }

At this point it contains a map of my entities which are mapped correctly, except every key (FinancialCategory) has an ID of 0. Any ideas why this happens?

I am storing this like so:

override fun addCategory(intent: FinancialRecordIntent.AddFinanceCategory) {
        viewModelScope.launch(Dispatchers.IO) {
             repository.storeCategory(category = intent.category)
        }
}

Solution

  • For anyone having the same issue. There seems to be a bug directly in Room. It seems that if you are relating tables with @Embedded the column names must not have the same name. For example

    data class FinancialCategory(
        @PrimaryKey(autoGenerate = true)
        @ColumnInfo
        val id: Long = 0L,
    )
    
    @Entity(
        tableName = "FinancialRecords",
        foreignKeys = [ForeignKey(
            entity = FinancialCategory::class,
            parentColumns = ["id"],
            childColumns = ["category"],
            onDelete = ForeignKey.CASCADE
        )],
        indices = [Index(value = ["category"], unique = false)]
    )
    data class FinancialRecord(
        @PrimaryKey(autoGenerate = true)
        val id: Long = 0L,
        ...
    
    )
    

    Won't work. It seems like room can not identify properly the entities with db columns but giving the columns in the entities unique names seems to work fine:

    data class FinancialCategory(
        @PrimaryKey(autoGenerate = true)
        @ColumnInfo(name = "parentId"
        val id: Long = 0L,
    )
    
    @Entity(
        tableName = "FinancialRecords",
        foreignKeys = [ForeignKey(
            entity = FinancialCategory::class,
            parentColumns = ["parentId"],
            childColumns = ["category"],
            onDelete = ForeignKey.CASCADE
        )],
        indices = [Index(value = ["category"], unique = false)]
    )
    data class FinancialRecord(
        @PrimaryKey(autoGenerate = true)
        @ColumnInfo(name = "childId"
        val id: Long = 0L,
        ...
    
    )
    
    data class CategoryWithRecords(
        @Embedded
        val category: FinancialCategory,
    
        @Relation(
            parentColumn = "parentId",
            entityColumn = "category"
        )
        val records: List<FinancialRecord>
    )