Home > Back-end >  Kotmin Room crossRef Entity with keys having the same name
Kotmin Room crossRef Entity with keys having the same name

Time:02-27

I'm creating a CRUD factory. Basically all my entites will inherit from a BaseEntity with id as a primary key I'm trying to understand how to create a cross ref table for a M2M relationship. Here is a simplifyied example, without inheritance. ArticlesEntity have many MagasinsEntity and MagasinsEntity many ArticlesEntity. The Entity ArticlesMagasinsCrossRef is the junction

But both ArticlesEntity and MagasinsEntity have id as the primaryKey.

@Entity(
    tableName = "articles"
)
data class ArticlesEntity(
    @PrimaryKey(autoGenerate = false) val id: UUID = UUID.randomUUID(),
    val title: String,
)

@Entity(tableName = "magasins")
data class MagasinsEntity(
    @PrimaryKey(autoGenerate = false) val id: UUID = UUID.randomUUID(),
    val nomMagasin: String

)

@Entity(
    tableName = "articles_magasins"
   )

data class ArticlesMagasinsCrossRefEntity(
    val id: UUID, // how is it possible here to have the id of Articles ?
    val id: UUID // how is it possible here to have the id of Magasins ?
)

Edit I tried of course to change the name of the columns:

data class ArticlesMagasinsCrossRefEntity(
            val articleRd: UUID
            val magasinId: UUID 
        )

but the build failed for the relation data class :for example

data class RelMagasinWithArticles(

    @Embedded val magasin: MagasinsEntity,
    @Relation(
        parentColumn = "magasinId",
        entityColumn = "id",
        associateBy = Junction(ArticlesMagasinsCrossRefEntity::class)
    )
    val articles: List<ArticleEntity>

)

enter image description here

CodePudding user response:

You need to use the Junction's parentColumn and entityColumn parameters e.g.

data class RelMagasinWithArticles(

    @Embedded val magasin: MagasinsEntity,
    @Relation(
        parentColumn = "id", /* The column in the @Embedded table (articles) */
        entityColumn = "id", /* The column in the Related table (magasins) */
        associateBy = Junction(
            ArticlesMagasinsCrossRefEntity::class,
            parentColumn = "magasinId", /* The column in the junction table that maps to the @Embedded table */
            entityColumn = "articleRd" /* The column in the junction table that maps to the @Relation Table */
        )
    )
    val articles: List<ArticlesEntity>
)

Note

You will also need to define a primary key for the ArticlesMagasinsCrossRefEntity class e.g. :-

@Entity(
    tableName = "articles_magasins",
    /*<<<<< all Room table MUST have a primary key */
    /* as primary key on a single column would be restrictive use a composite
        primary key
     */
    primaryKeys = ["articleRd","magasinId"] 
)

data class ArticlesMagasinsCrossRefEntity(

    /* Cannot have identical member names - i.e. only 1 could be id
    val id: UUID, // how is it possible here to have the id of Articles ?
    val id: UUID // how is it possible here to have the id of Magasins ?
     */
    val articleRd: UUID,
    /* Room will issue warning if the is no index on the 2nd column */
    @ColumnInfo(index = true)
    val magasinId: UUID
)
  • note that you can use the @ColumnInfo name parameter to specify column names.

Demonstration

So using you code with the suggested code overriding your code and with the following @Dao interface:-

@Dao
interface AllDao {

    @Insert
    fun insert(articlesEntity: ArticlesEntity)
    @Insert
    fun insert(magasinsEntity: MagasinsEntity)
    @Insert
    fun insert(articlesMagasinsCrossRefEntity: ArticlesMagasinsCrossRefEntity)

    @Query("SELECT * FROM magasins")
    @Transaction
    fun getMWA(): List<RelMagasinWithArticles>
}

a suitable @Database annotated class and code in the activity:-

lateinit var db: TheDatabase
lateinit var dao: AllDao
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    db = TheDatabase.getInstance(this)
    dao = db.getAllDao()

    val a1uuid = UUID.randomUUID()
    val a2uuid = UUID.randomUUID()
    val a3uuid = UUID.randomUUID()
    dao.insert(ArticlesEntity(a1uuid, "Article1"))
    dao.insert(ArticlesEntity(a2uuid,"Article2"))
    dao.insert(ArticlesEntity(a3uuid,"Article3"))

    val m1uuid = UUID.randomUUID()
    val m2uuid = UUID.randomUUID()
    val m3uuid = UUID.randomUUID()
    dao.insert(MagasinsEntity(m1uuid,"Magasin1"))
    dao.insert(MagasinsEntity(m2uuid,"Magasin2"))
    dao.insert(MagasinsEntity(m3uuid,"Magasin3"))

    dao.insert(ArticlesMagasinsCrossRefEntity(a1uuid,m2uuid))
    dao.insert(ArticlesMagasinsCrossRefEntity(a1uuid,m3uuid))

    dao.insert(ArticlesMagasinsCrossRefEntity(a2uuid,m1uuid))

    dao.insert(ArticlesMagasinsCrossRefEntity(a3uuid,m1uuid))
    dao.insert(ArticlesMagasinsCrossRefEntity(a3uuid,m2uuid))
    dao.insert(ArticlesMagasinsCrossRefEntity(a3uuid,m3uuid))

    val sb = StringBuilder()
    for(mwa in dao.getMWA()) {
        sb.append("\nMagasin is ${mwa.magasin.nomMagasin}. ID is ${mwa.magasin.id} it has ${mwa.articles.size} articles. They are:-" )
        for (article in mwa.articles) {
            sb.append("\n\tArticle is ${article.title} ID is ${article.id}")
        }
    }
    Log.d("DBINFO",sb.toString())
}

The output to the log is:-

D/DBINFO: Magasin is Magasin1. ID is 0f3384ee-6232-423e-b2f1-a12ebdac6487 it has 2 articles. They are:-
        Article is Article2 ID is 2729d017-de05-41d2-8de3-8351dfca0a6b
        Article is Article3 ID is 42057ea7-bc03-409f-b2b8-2dc3fa5def19
    Magasin is Magasin2. ID is ba649833-a8ce-4cf2-a1b8-bcab8f7a7d0a it has 2 articles. They are:-
        Article is Article1 ID is 8763421d-b86d-4725-8e6b-65570958ebdc
        Article is Article3 ID is 42057ea7-bc03-409f-b2b8-2dc3fa5def19
    Magasin is Magasin3. ID is eed6f0a5-0825-4cda-9eb4-c4e973a49738 it has 2 articles. They are:-
        Article is Article1 ID is 8763421d-b86d-4725-8e6b-65570958ebdc
        Article is Article3 ID is 42057ea7-bc03-409f-b2b8-2dc3fa5def19
  • Related