Die Room Persistence Library von Android enthält freundlicherweise die Anmerkungen @Insert und @Update, die für Objekte oder Sammlungen funktionieren. Ich habe jedoch einen Anwendungsfall (Push-Benachrichtigungen, die ein Modell enthalten), für den ein UPSERT erforderlich wäre, da die Daten möglicherweise in der Datenbank vorhanden sind oder nicht.
Sqlite hat kein Upsert von Haus aus, und Problemumgehungen werden in dieser SO-Frage beschrieben . Wie würde man die dortigen Lösungen auf Room anwenden?
Wie kann ich eine Einfügung oder Aktualisierung in Room implementieren, die keine Fremdschlüsseleinschränkungen aufhebt? Wenn Sie insert mit onConflict = REPLACE verwenden, wird onDelete für jeden Fremdschlüssel für diese Zeile aufgerufen. In meinem Fall verursacht onDelete eine Kaskade, und das erneute Einfügen einer Zeile führt dazu, dass Zeilen in anderen Tabellen mit dem Fremdschlüssel gelöscht werden. Dies ist NICHT das beabsichtigte Verhalten.
Für eine elegantere Vorgehensweise würde ich zwei Optionen vorschlagen:
Überprüfen auf Rückgabewert aus der
insert
Operation mitIGNORE
alsOnConflictStrategy
(wenn er gleich -1 ist, bedeutet dies, dass keine Zeile eingefügt wurde):Umgang mit Ausnahme von
insert
Betrieb mitFAIL
alsOnConflictStrategy
:quelle
Ich konnte keine SQLite-Abfrage finden, die eingefügt oder aktualisiert werden konnte, ohne unerwünschte Änderungen an meinem Fremdschlüssel zu verursachen. Stattdessen habe ich mich dafür entschieden, zuerst einzufügen, Konflikte zu ignorieren, wenn sie auftraten, und unmittelbar danach zu aktualisieren und Konflikte erneut zu ignorieren.
Die Einfüge- und Aktualisierungsmethoden sind geschützt, sodass externe Klassen nur die Upsert-Methode sehen und verwenden. Beachten Sie, dass dies kein echter Upsert ist, da die MyEntity-POJOS über Nullfelder verfügen und die derzeit in der Datenbank enthaltenen Daten möglicherweise überschreiben. Dies ist keine Einschränkung für mich, aber es kann für Ihre Anwendung sein.
quelle
upsert
Methode besser mit der@Transaction
AnmerkungWenn die Tabelle mehr als eine Spalte enthält, können Sie verwenden
eine Zeile ersetzen.
Referenz - Gehen Sie zu den Tipps für Android Room Codelab
quelle
deferred = true
die Entität mit dem Fremdschlüssel festlegen .Dies ist der Code in Kotlin:
}}
quelle
null values
ich damit um, wo ich nicht mit null aktualisieren möchte, sondern den alten Wert beibehalten möchte. ?Nur ein Update, wie dies gemacht werden kann, wenn Kotlin die Daten des Modells beibehält (möglicherweise, um sie wie im Beispiel in einem Zähler zu verwenden):
Sie können auch die Variable @Transaction und den Datenbankkonstruktor für komplexere Transaktionen verwenden, indem Sie database.openHelper.writableDatabase.execSQL ("SQL STATEMENT") verwenden.
quelle
Ein anderer Ansatz, den ich mir vorstellen kann, besteht darin, die Entität per Abfrage über DAO abzurufen und dann alle gewünschten Aktualisierungen durchzuführen. Dies ist im Vergleich zu den anderen Lösungen in diesem Thread in Bezug auf die Laufzeit möglicherweise weniger effizient, da die vollständige Entität abgerufen werden muss, bietet jedoch viel mehr Flexibilität hinsichtlich der zulässigen Vorgänge, z. B. hinsichtlich der zu aktualisierenden Felder / Variablen.
Zum Beispiel :
quelle
Sollte mit dieser Art von Aussage möglich sein:
quelle
ON CONFLICT UPDATE SET a = 1, b = 2
wird vonRoom
@Query
Annotation nicht unterstützt .