Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity list relationships in Android Room

I'm trying to load entity sublist, but i would like to avoid to do 2 queries.

I'm thinking about do query inside TypeConverter, but i really don't know if it's good idea.

My entities:

@Entity
class Region(
        @PrimaryKey(autoGenerate = true)
        var id: Int = 0,
        var name: String = "",
        var locales: List<Locale> = listOf())

@Entity(foreignKeys = arrayOf(ForeignKey(
        entity = Region::class,
        parentColumns = arrayOf("id"),
        childColumns = arrayOf("regionId"),
        onDelete = CASCADE,
        onUpdate = CASCADE
)))
class Locale(
        @PrimaryKey(autoGenerate = true)
        var id: Int = 0,
        var regionId: Int = 0,
        var name: String = "")

DAOs :

@Dao
interface RoomRegionDao{
    @Insert
    fun insert(region: Region)

    @Delete
    fun delete(region: Region)

    @Query("select * from region")
    fun selectAll(): Flowable<List<Region>>
}

@Dao
interface RoomLocaleDao{
    @Insert
    fun insert(locale: Locale)

    @Query("select * from locale where regionId = :arg0")
    fun selectAll(regionId: Int): List<Locale>
}

Database:

@Database(entities = arrayOf(Region::class, Locale::class), version = 1)
@TypeConverters(RoomAppDatabase.Converters::class)
abstract class RoomAppDatabase : RoomDatabase() {
    abstract fun regionDao(): RoomRegionDao
    abstract fun localeDao(): RoomLocaleDao

    inner class Converters {
        @TypeConverter
        fun toLocales(regionId: Int): List<Locale> {
            return localeDao().selectAll(regionId)
        }

        @TypeConverter
        fun fromLocales(locales: List<Locale>?): Int {
            locales ?: return 0
            if (locales.isEmpty()) return 0

            return locales.first().regionId
        }
    }
}

It's not working because can't use inner class as converter class.

  • Is it a good way?
  • How can I load "locales list" automatically in region entity when I do RoomRegionDao.selectAll?
like image 589
Lyofen Avatar asked May 27 '17 13:05

Lyofen


2 Answers

I think that TypeConverter only works for static methods. I say this based on the example from here and here

From the relationships section here:

"Because SQLite is a relational database, you can specify relationships between objects. Even though most ORM libraries allow entity objects to reference each other, Room explicitly forbids this."

So I guess it's best if you add @Ignore on your locales property and make a method on RoomLocaleDao thats insert List<Locale> and call it after insert Region.

The method that inserts a Region can return the inserted id.

If the @Insert method receives only 1 parameter, it can return a long, which is the new rowId for the inserted item. If the parameter is an array or a collection, it should return long[] or List instead. (https://developer.android.com/topic/libraries/architecture/room.html#daos-convenience)

like image 100
Pietro Caselani Avatar answered Sep 30 '22 05:09

Pietro Caselani


You can get all your Regions wit a list of Locales inside each Region just with one Query.

All you need to do is create a new Relation like this:

data class RegionWithLocale(
    @Embedded
    val region: Region,
    @Relation(
        parentColumn = "id",
        entity = Locale::class,
        entityColumn = "regionId"
    )
    val locales: List<Locale>
)

And latter get that relation in your Dao like this:

@Query("SELECT * FROM region WHERE id IS :regionId")
fun getRegions(regionId: Int): LiveData<RegionWithLocale>

@Query("SELECT * FROM region")
fun getAllRegions(): LiveData<List<RegionWithLocale>>
like image 39
Osvel Alvarez Jacomino Avatar answered Sep 30 '22 04:09

Osvel Alvarez Jacomino