Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Room database with one-to-one relation

I have 2 Entities, Coin and CoinRevenue.

Basically, coin holds the price in USD for some other currency.

For example, Coin with symbol EUR with value of 1.0356

@Entity(tableName = "coin")
data class Coin(
        @field:PrimaryKey(autoGenerate = false)
        var id: String = "",
        var symbol: String = "",
        var pricInUsd: Float = 0f)

CoinRevenue is an Entity that I use to hold how much coins of that specific coins the User have. For example, CoinRevenue has relation to Coin Entity with EUR symbol and amount of 1000.

@Entity(tableName = "coinRevenue")
    data class CoinRevenueNew(
            @field:PrimaryKey(autoGenerate = true)
            var id: Int = 0,
            var coin: Coin? = null,
            var amount: Float = 0f)

Now I want to fetch CoinRevenue from the database and get the updated Coin from the database.

for example, i saved the Coin with (EUR,1.0253) and than Saved a CoinRevenue with that coin.

After that I updated the Coin with (EUR,2.522) I want that the Coin object inside CoinRevenue will be updated as well.

I understand that @Embedded just add the inner objet fields as colums to the same parent object. and when I use relation, I have to use a List or a Set. but I always have 1 Coin inside CoinRevenue.

My coinDAO:

@Query("select * from coin order by rank")
fun getAllCoins(): Flowable<List<CoinDB>>

@Query("select * from coin where rank = 1")
fun getFirstCoin(): Maybe<CoinDB>

@Query("select * from coin where favourite = 1 order by rank")
fun getAllFavouriteCoins(): Flowable<List<CoinDB>>

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertCoin(coinDB: CoinDB)

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertCoins(coinsList: List<CoinDB>)

// -----------------
// CoinRevenue
// -----------------

@Query("select * from coinRevenue order by rank")
fun getAllCoinsRevenue(): Flowable<List<CoinRevenue>>

@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertCoinRevenue(coinRevenue: CoinRevenue)

@Delete()
fun deleteCoinRevenue(coinRevenue: CoinRevenue)

What is the best way to creat this?

like image 951
Shahar Avatar asked Jan 03 '18 14:01

Shahar


People also ask

What is a 1 1 relationship in database?

A one-to-one relationship is a link between the information in two tables, where each record in each table only appears once. For example, there might be a one-to-one relationship between employees and the cars they drive.

Is room a relational database?

Because SQLite is a relational database, you can define relationships between entities. Even though most object-relational mapping libraries allow entity objects to reference each other, Room explicitly forbids this.

How would you insert entities with a one-to-many relationship in a room?

Android one to many in room explanation: Add the @Relation annotation to the instance of the child entity, with parentColumn set to the name of the primary key column of the parent entity and entityColumn set to the name of the column of the child entity that references the parent entity's primary key.

What is an example of a one-to-many relationship?

Some common examples of one-to-many relationships are: A car maker makes many different models, but a particular car model is built only by a single car maker. One customer may make several purchases, but each purchase is made by a single customer.


2 Answers

So after a lot of tries, I've managed to get it working.

I Changed the CoinRevenue object to hold a foreign key to the Coin id

@Entity(tableName = "coinRevenue", foreignKeys = (arrayOf(ForeignKey(
        entity = CoinDB::class,
        onUpdate = ForeignKey.CASCADE,
        parentColumns = arrayOf("coinId"),
        childColumns = arrayOf("coinDbId"))))
)
data class CoinRevenue(
        @ColumnInfo(name = "mid")
        @PrimaryKey(autoGenerate = true)
        var id: Long = 0L,
        @ColumnInfo(name = "coinDbId")
        var coinDbId: String? = null,
        @ColumnInfo(name = "amount")
        var amount: Double = 0.toDouble()
)

I needed to create a POJO with both objects, like that:

class CoinRevenueWithCoin() : Parcelable {
@Embedded lateinit var coinDB: CoinDB
@Embedded lateinit var coinRevenue: CoinRevenue
}

and the query it like this:

@Query("select * from coinRevenue, coin where coinRevenue.coinDbId = coin.coinId order by coin.rank")
fun getAllCoinsRevenueWithCoin(): Flowable<List<CoinRevenueWithCoin>>

That's it.

In addition this query, as any other regular objects query, emit objects if there is any change in the 'coin' table or the 'coinRevenue' table

like image 108
Shahar Avatar answered Oct 08 '22 02:10

Shahar


Your solution has several major drawback. One of them is that the tables' columns has to have different names. Instead of using @embededed I suggest to apply @Relation.

@Entity(tableName = "coin")
data class Coin(
        @field:PrimaryKey(autoGenerate = false)
        var id: String = "",
        var symbol: String = "",
        var pricInUsd: Float = 0f)

@Entity(tableName = "coinRevenue", foreignKeys = (arrayOf(ForeignKey(
        entity = CoinDB::class,
        onUpdate = ForeignKey.CASCADE,
        parentColumns = arrayOf("coinId"),
        childColumns = arrayOf("coinDbId"))))
)
data class CoinRevenue(
        @ColumnInfo(name = "mid")
        @PrimaryKey(autoGenerate = true)
        var id: Long = 0L,
        @ColumnInfo(name = "coinDbId")
        var coinDbId: String? = null,
        @ColumnInfo(name = "amount")
        var amount: Double = 0.toDouble()
) 

I am not familiar with Kotlin so the solution is in Java

class CoinRevenueExt extends CoinRevenue {
        @Relation(parentColumn = "coinDbId", entityColumn = "coinId" ) 
        List<Coin> coins;

        public Coin getCoin() {
            return coins.get(0);
        }

}

And Dao is simple as that

@Query("select * from coinRevenue")
public Flowable<List<CoinRevenueExt>> getAllCoinsRevenueWithCoin();
like image 6
sim Avatar answered Oct 08 '22 02:10

sim