it-swarm.com.de

Raumdatenbank mit Eins-zu-Eins-Beziehung

Ich habe 2 Entitäten, Münzen und Münzen.

Grundsätzlich hält eine Münze den Preis in USD für eine andere Währung.

Beispiel: Münze mit dem Symbol EUR mit dem Wert 1,0356

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

CoinRevenue ist eine Entität, die ich verwende, um zu halten, wie viel Münzen dieser bestimmten Münzen der Benutzer hat ..__ Zum Beispiel hat CoinRevenue eine Beziehung zu Coin Entity mit dem EUR-Symbol und einem Betrag von 1000.

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

Jetzt möchte ich CoinRevenue aus der Datenbank abrufen und die aktualisierte Münze aus der Datenbank holen.

zum Beispiel habe ich die Münze mit (EUR, 1.0253) und dann mit dieser Münze ein CoinRevenue gespeichert.

Danach habe ich die Münze mit (EUR, 2.522) .__ aktualisiert. Ich möchte, dass auch das Münzobjekt in CoinRevenue aktualisiert wird.

Ich verstehe, dass @Embedded einfach die inneren Objektfelder als Spalten zum selben übergeordneten Objekt hinzufügt Wenn ich Relation verwende, muss ich eine Liste oder ein Set verwenden Ich habe jedoch immer 1 Münze in CoinRevenue.

Meine MünzeDAO:

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

Was ist der beste Weg, um dies zu schaffen?

7
Shahar

Nach vielen Versuchen habe ich es geschafft, es zum Laufen zu bringen.

Ich habe das CoinRevenue-Objekt so geändert, dass es einen Fremdschlüssel für die Münzen-ID enthält

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

Ich musste ein POJO mit beiden Objekten erstellen:

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

und die Abfrage es so:

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

Das ist es.

Zusätzlich zu dieser Abfrage werden bei jeder anderen regulären Objektabfrage Objekte ausgegeben, wenn sich in der Tabelle "Münze" oder in der Tabelle "coinRevenue" Änderungen ergeben

10
Shahar

Ihre Lösung hat mehrere schwerwiegende Nachteile. Eine davon ist, dass die Tabellenspalten unterschiedliche Namen haben müssen. Anstelle von @embededed schlage ich vor, @Relation anzuwenden.

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

Ich bin mit Kotlin nicht vertraut, daher ist die Lösung in Java

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

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

}

Und Dao ist so einfach 

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

Es ist ein bisschen schwer zu sagen, was Sie wirklich erreichen wollen. Auch Ihre Benennung ist etwas seltsam. Es scheint, dass die Münztabelle wirklich die Währungsinformationen enthält. Die coinRevenueNew ist eine Buchung oder ein Auftrag. Wenn Sie sich leichter für Beispiele entscheiden, werden mehr Leute versuchen, Ihre Beiträge zu lesen.

Das Problem, das Sie zu lösen versuchen, ist ein wenig unklar. Ist das Problem bei der Modellierung in der Datenbank? Ist das Problem, dass alle Beträge automatisch aktualisiert werden sollen, wenn sich die Währung ändert? __.- Ist Ihr Problem, dass die Objekte im Speicher aktualisiert werden sollen, wenn sich die Datenbank ändert? __.- Ist Ihr Problem bei der Verwendung von Fremdschlüsseln mit Room?

Das erste Problem mit dem Modellieren wurde von anderen Personen angedeutet. Sie verwenden einen Fremdschlüssel. Es gibt viele Artikel darüber.

Mit etwas verständlicheren Domainnamen hätten Sie zwei Tabellen wie diese:

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

Sie würden für jeden Raum Entitäten erstellen. Sie würden eine dritte Klasse erstellen (markieren Sie sie nicht mit @Entity), die beide kombiniert. Sie können hier die Annotationen @Embedded oder @Relation verwenden. Die Dokumentation erklärt dies weiter:

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

Wenn Sie die Währung ändern, aktualisiert das Speichersystem nicht automatisch alle Auftragssummen. Wenn Sie ein Feld "total_in_foreign_currency" und ein Feld "total_in_master_currency" haben, wird die Datenbank für Sie nicht neu berechnet. Sie müssen jede Zeile manuell durchlaufen und sie neu berechnen.

Im Speicher werden Datenobjekte nicht magisch aktualisiert. Sie müssen nachverfolgen, wann Sie die Daten abgerufen haben und ob sie sich noch befinden. Sie können LiveData verwenden, um bei jeder Änderung der Daten benachrichtigt zu werden (Ihre Objekte werden jedoch nicht auf magische Weise aktualisiert).

0
Thomas Fischer