Solution 1 :
I made it work on my own.
As I thought the main problem was the autogenerated int key of Licence used as foreign key. A “static” string and splitting the two objects in the @Insert method did the trick.
I’ll leave it here, hope it helps someone:
Licence:
@Entity(tableName = "licence")
data class Licence(
@PrimaryKey
@ColumnInfo(name = "function_id")
var functionId: String,
@ColumnInfo(name = "expiration_date")
var expirationDate: Date,
//more attributes )
LicenceConfigurations:
@Entity(
foreignKeys = [
ForeignKey(
entity = Licence::class,
parentColumns = ["function_id"],
childColumns = ["licence_reference"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
)],tableName = "licence_configurations")
data class LicenceConfig(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "licence_config_id")
var licenceConfigId: Int,
@ColumnInfo(name = "licence_reference")
var licenceId: Int
//more attributes )
LicenceWithConfigurations:
data class LicenceWithConfigurations(
@Embedded
val licence: Licence,
@Relation(
parentColumn = "licence_id",
entityColumn = "licence_reference",
entity = LicenceConfig::class)
val licenceConfig: List<LicenceConfig>?)
LicenceDao:
@Transaction
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertLicenceWithConfigurations(licence:Licence, licenceConfigurations: List<LicenceConfig>?)
@Transaction
@Query("SELECT * FROM licence")
suspend fun getAllLicencesWithConfigurations(): List<LicenceWithConfigurations>
Problem :
I’ve read a ton of q/a and articles about room and foreign keys and I’m almost convinced that I can’t actually achieve what I’m trying to do. Also most of the examples/tutorials explain only select query.
So, there’s a classic one to many relationship and I would like to define an object with @Embedded and @Relation to obtain an “one shot” insert method for an object containing a list of objects.
To be more clear:
Licence:
@Entity(tableName = "licence")
data class Licence(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "licence_id")
var licenceId: Int,
@ColumnInfo(name = "expiration_date")
var expirationDate: Date
//other attributes )
LicenceConfigurations:
@Entity(
foreignKeys = [
ForeignKey(
entity = Licence::class,
parentColumns = ["licence_id"],
childColumns = ["licence_reference"],
onDelete = ForeignKey.CASCADE,
onUpdate = ForeignKey.CASCADE
)],
tableName = "licence_configurations")
data class LicenceConfig(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "licence_config_id")
var licenceConfigId: Int,
@ColumnInfo(name = "licence_reference")
var licenceId: Int
//other attributes )
LicenceWithConfigurations
data class LicenceWithConfigurations(
@Embedded
val licence: Licence,
@Relation(
parentColumn = "licence_id",
entityColumn = "licence_reference",
entity = LicenceConfig::class)
val licenceConfig: List<LicenceConfig>?)
What I’m trying to do is to avoid @Transaction and perform the first insert for Licence, retrieve the id, set the id for each LicenceConfiguration and perform another insert.
I would like instead to have a method like that in the DAO:
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertLicenceWithConfigurations(licenceWithConfigurations: LicenceWithConfigurations)
Right now the error is “FOREIGN KEY constraint failed (code 787 SQLITE_CONSTRAINT_FOREIGNKEY)”, so I have specified the @Index for LicenceConfig class then tried to set the foreign key on another field (because I have read that with autogenerated id as foreign keys it will not works) but is still not working. Can I do that or should I go back with @Transaction and handle the insertions manually?