La bibliothèque de persistance Room d'Android comprend gracieusement les annotations @Insert et @Update qui fonctionnent pour les objets ou les collections. J'ai cependant un cas d'utilisation (notifications push contenant un modèle) qui nécessiterait un UPSERT car les données peuvent ou non exister dans la base de données.
Sqlite n'a pas d'upsert nativement, et les solutions de contournement sont décrites dans cette question SO . Compte tenu des solutions, comment les appliquerait-on à Room?
Pour être plus précis, comment puis-je implémenter une insertion ou une mise à jour dans Room qui ne briserait aucune contrainte de clé étrangère? L'utilisation d'insert avec onConflict = REPLACE entraînera l'appel de onDelete pour toute clé étrangère de cette ligne. Dans mon cas, onDelete provoque une cascade, et la réinsertion d'une ligne entraînera la suppression de lignes dans d'autres tables avec la clé étrangère. Ce n'est PAS le comportement prévu.
Pour une manière plus élégante de le faire, je suggérerais deux options:
Vérification de la valeur de retour de l'
insert
opération avecIGNORE
as aOnConflictStrategy
(si elle est égale à -1, cela signifie que la ligne n'a pas été insérée):Traitement de l'exception d'
insert
opération avecFAIL
commeOnConflictStrategy
:la source
Je n'ai pas pu trouver de requête SQLite qui s'insérerait ou se mettrait à jour sans provoquer de modifications indésirables de ma clé étrangère.J'ai donc choisi d'insérer d'abord, en ignorant les conflits s'ils se produisaient et en mettant à jour immédiatement après, en ignorant à nouveau les conflits.
Les méthodes d'insertion et de mise à jour sont protégées afin que les classes externes voient et utilisent uniquement la méthode upsert. Gardez à l'esprit que ce n'est pas un véritable upsert, car si l'un des POJOS MyEntity avait des champs nuls, ils écraseraient ce qui peut actuellement se trouver dans la base de données. Ce n'est pas une mise en garde pour moi, mais peut-être pour votre application.
la source
upsert
méthode avec l'@Transaction
annotationSi la table comporte plus d'une colonne, vous pouvez utiliser
pour remplacer une ligne.
Référence - Aller aux astuces Android Room Codelab
la source
deferred = true
de l'entité avec la clé étrangère.Voici le code de Kotlin:
}
la source
null values
où je ne veux pas mettre à jour avec null mais conserver l'ancienne valeur. ?Juste une mise à jour pour savoir comment faire cela avec Kotlin en conservant les données du modèle (peut-être pour l'utiliser dans un compteur comme dans l'exemple):
Vous pouvez également utiliser @Transaction et la variable de constructeur de base de données pour des transactions plus complexes en utilisant database.openHelper.writableDatabase.execSQL ("SQL STATEMENT")
la source
Une autre approche à laquelle je peux penser est d'obtenir l'entité via DAO par requête, puis d'effectuer les mises à jour souhaitées. Cela peut être moins efficace par rapport aux autres solutions de ce thread en termes d'exécution en raison de la nécessité de récupérer l'entité complète, mais permet beaucoup plus de flexibilité en termes d'opérations autorisées telles que sur les champs / variables à mettre à jour.
Par exemple :
la source
Devrait être possible avec ce type de déclaration:
la source
ON CONFLICT UPDATE SET a = 1, b = 2
n'est pas pris en charge par l'Room
@Query
annotation.