web-dev-qa-db-fra.com

Base de données de salles avec relation un à un

J'ai 2 entités, Coin et CoinRevenue.

Fondamentalement, la pièce contient le prix en USD pour une autre devise.

Par exemple, une pièce avec le symbole EUR d’une valeur de 1,0356.

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

CoinRevenue est une entité que j'utilise pour stocker le nombre de pièces de cet utilisateur spécifique que possède l'utilisateur. Par exemple, CoinRevenue a une relation avec Entity avec un symbole en EUR et un montant de 1 000.

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

Maintenant, je veux récupérer CoinRevenue de la base de données et obtenir la pièce mise à jour à partir de la base de données.

par exemple, j’ai sauvé la pièce avec (EUR, 1,0253) et qu’il a sauvegardé un CoinRevenue avec cette pièce.

Après cela, j'ai mis à jour la pièce avec (2,522 EUR) Je souhaite que l'objet Pièce de CoinRevenue soit également mis à jour.

Je comprends que @Embedded ajoute simplement les champs d’objet intérieurs en tant que colonnes au même objet parent . Et lorsque j’utilise relation, je dois utiliser une liste ou un ensemble . Mais j’ai toujours 1 pièce dans CoinRevenue.

Mon 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)

Quel est le meilleur moyen de créer cela?

7
Shahar

Donc, après beaucoup d'essais, j'ai réussi à le faire fonctionner.

J'ai modifié l'objet CoinRevenue pour conserver une clé étrangère sur l'identifiant Coin

@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()
)

J'avais besoin de créer un POJO avec les deux objets, comme ça:

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

et la requête se présente comme ceci:

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

C'est tout.

De plus, cette requête, comme toute requête d’objets standard, émet des objets en cas de modification de la table 'coin' ou de la table 'coinRevenue'.

10
Shahar

Votre solution présente plusieurs inconvénients majeurs. L'une d'elles est que les colonnes des tables doivent avoir des noms différents. Au lieu d'utiliser @embededed, je suggère d'appliquer @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()
) 

Je ne connais pas bien Kotlin, la solution est donc en Java

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

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

}

Et Dao est simple comme ça 

@Query("select * from coinRevenue")
public Flowable<List<CoinRevenueExt>> getAllCoinsRevenueWithCoin();
2
sim

C'est un peu difficile de dire ce que vous essayez vraiment de réaliser. De plus, votre nom est un peu étrange. Il semble que la table des pièces contienne vraiment les informations sur la devise. CoinRevenueNew est une entrée au grand livre ou une commande. Si vous choisissez plus facilement de suivre des exemples, plus de personnes essaieront de finir de lire vos messages.

En outre, le problème que vous essayez de résoudre est un peu incertain .- Votre problème est-il modélisé dans la base de données? - Votre problème est-il que vous souhaitiez que tous les montants soient automatiquement mis à jour lorsque la devise change? __.- Votre problème est-il que vous souhaitiez que les objets en mémoire soient mis à jour lorsque la base de données change? - Votre problème concerne-t-il l'utilisation de clés étrangères avec Room?

Le premier problème avec la modélisation a été évoqué par d'autres personnes. Vous utilisez une clé étrangère. Il y a beaucoup d'articles à ce sujet.

En utilisant des noms de domaine un peu plus compréhensibles, vous auriez deux tables comme celles-ci:

create table currency (id integer primary key, exchange_rate float);
create table order (id integer primary key, int total, int currency_id, foreign key(currency_id) references currency(id));

Vous créez des entités de pièce pour chacun. Vous créez une troisième classe (ne la marquez pas avec @Entity) qui combine les deux. Vous pouvez utiliser les annotations @Embedded ou @Relation ici. La documentation explique ceci plus loin:

https://developer.Android.com/reference/Android/Arch/persistence/room/Relation.html

Si vous changez la devise, le système de stockage ne mettra pas automatiquement à jour tous les totaux de commande. Si vous avez un champ "total_in_foreign_currency" et un champ "total_in_master_currency", la base de données ne sera pas recalculée pour vous. Vous devez parcourir manuellement chaque ligne et la recalculer.

En mémoire, les objets de données ne sont pas mis à jour par magie. Vous devez savoir quand vous avez récupéré les données et si elles le sont toujours. Vous pouvez utiliser LiveData pour être averti chaque fois que les données changent (mais cela ne mettra pas vos objets à jour par magie).

0
Thomas Fischer