Reputation: 1000
I have the following Kotlin entities for Room ver. 2.2.5.
PARENT ENTITY
@Entity(tableName = "ITEM",
indices = [Index(value = ["id"], unique = true), Index(value = ["code"], unique = true), Index(value = ["status"], unique = false)]
)
data class Item (
@PrimaryKey @ColumnInfo(name = "id") override val id: UUID = UUID.randomUUID(),
@ColumnInfo(name = "code") @NotNull val code: String,
@ColumnInfo(name = "valid") val valid: Boolean = true,
@ColumnInfo(name = "value") val value: Double?,
@ColumnInfo(name = "price") val price: Double?,
@ColumnInfo(name = "default_description") val defaultDescription: String?,
@ColumnInfo(name = "description") val description: String?
)
CHILD ENTITY
@Entity(tableName = "LOCATION",
indices = [Index(value = ["id"], unique = true), Index(value = ["code"], unique = true)]
)
data class Location (
@ColumnInfo(name = "id") @PrimaryKey override val id: UUID = UUID.randomUUID(),
@ColumnInfo(name = "code") val code: String,
@ColumnInfo(name = "latitude") val latitude: Double?,
@ColumnInfo(name = "longitude") val longitude: Double?,
@ColumnInfo(name = "default_description") val defaultDescription: String?
)
JUNCTION ENTITY
@Entity(
tableName = "ITEM_LOCATION_L",
primaryKeys = [
"item_id", "location_id"
],
foreignKeys = [
ForeignKey(entity = Item::class, parentColumns = ["id"], childColumns = ["item_id"]),
ForeignKey(entity = Location::class, parentColumns = ["id"], childColumns = ["location_id"])
],
indices = [
Index("id"),
Index("item_id"),
Index("location_id")])
data class ItemLocationLink (
@ColumnInfo(name = "id") override val id: UUID = UUID.randomUUID(),
@ColumnInfo(name = "item_id") val itemId: UUID, /** Item ID - parent entity */
@ColumnInfo(name = "location_id") val locationId: UUID, /** Location ID - child entity */
@ColumnInfo(name = "quantity") val quantity: Double /** Quantity of the item in the referenced location */
)
RESULT CLASS
class ItemLocationRelation {
@Embedded
lateinit var item: Item
@Relation(
parentColumn = "id",
entityColumn = "id",
associateBy = Junction(value = ItemLocationLink::class, parentColumn = "item_id", entityColumn = "location_id")
) lateinit var locations: List<Location>
}
DAO INTERFACE
@Dao
interface ItemLocationLinkDao {
@Transaction
@Query("SELECT * FROM ITEM WHERE id = :itemId")
fun getLocationsForItem(itemId: UUID): List<ItemLocationRelation>
}
DATABASE TYPE CONVERTER
class DBTypesConverter {
@TypeConverter
fun fromUUID(uid: UUID?): String? {
if (uid != null)
return uid.toString()
return null
}
@TypeConverter
fun toUUID(str: String?): UUID? {
if (str != null) {
return UUID.fromString(str)
}
return null
}
@TypeConverter
fun fromDate(d: Date?): Long? {
return d?.time
}
@TypeConverter
fun toDate(l: Long?): Date? {
return if (l != null) Date(l) else null
}
}
When I call getLocationsForItem I get in return an instance of ItemLocationRelation with a valid Item but no child objects. I've checked the generated code and there is no sign of the Junction class. The generated code behaves like it is not a many-to-many relation, the Junction class is completely ignored, I can even specify a fake class in the @Junction attribute of the relation and the result would be exactly the same without errors.
If I add a function to the DAO class that returns the results of the following query:
select * from item
inner join item_location_l as link on link.item_id = item.id
inner join LOCATION as l on link.location_id = l.id
where item.id = '99a3a64f-b0e6-e911-806a-68ecc5bcbe06'
I get 2 rows as expected. So the SQLite database is ok. Please help.
Upvotes: 1
Views: 436
Reputation: 1000
So, in the end the problem was really subtle. For reasons I cannot explain the project I was working on had the following gradle settings (app gradle):
kapt "android.arch.persistence.room:compiler:2.2.5"
I replaced it with
kapt "androidx.room:room-compiler:2.2.5"
And then everything was fine. The hard-coded query generated by the plugin now contains the JOIN and it works....
Upvotes: 1