Après avoir structuré vos données avec les entités pour représenter les aspects clés de PETiSoin, l'étape suivante est de faciliter l'accès et la gestion de ces données.
Analysez votre besoin
Manipuler les données d’une base de données nécessite un prérequis : connaître l’ensemble des opérations qu’il est possible de faire sur celle-ci.
Prenez connaissance des opérations CRUD
Au cœur de Room, et des bases de données de manière plus générale, se trouve le concept de CRUD (Create, Read, Update et Delete).
Nom de l’opération | Objectif de l’opération | Nature de l’opération |
Create | Ajouter des nouvelles données à la base de données | Écriture |
Read | Récupérer des données de la base de données | Lecture |
Update | Mettre à jour (MAJ) les données existantes dans la base de données | Écriture |
Delete | Supprimer des données de la base de données | Écriture |
Définissez le besoin
Rapprochons ces quatre opérations fondamentales du besoin fonctionnel de l’application PETiSoin, à savoir la gestion des animaux et des notes associées.
L’ensemble des quatre opérations doit être implémentée pour les deux entités représentées par les classes Animal
etNotes
. Vous aurez donc besoin des opérations suivantes.
Création d’un animal.
Lecture des informations d’un animal.
Mise à jour des informations d’un animal.
Suppression de l’ensemble des informations d’un animal.
Récupération des informations de l’ensemble des animaux.
Création d’une note associée à un animal.
Lecture d’une note associée à un animal.
Mise à jour d’une note associée à un animal.
Suppression d’une note associée à un animal.
Récupération de l’ensemble des notes associées à un animal.
Définissez vos interfaces
Maintenant que les différentes opérations de l’application PETiSoin sont connues, il convient de les traduire sous la forme de code Java ou Kotlin et plus particulièrement sous la forme de DAO (Data Access Object ou objets pour accéder aux données).
Euh… C’est quoi un DAO ?
Le DAO est un patron de conception logiciel dont le but est de simplifier l'accès aux données d'une base de données. Il agit comme une interface qui facilite l’interaction entre l’application et la base de données en abstrayant les détails techniques de la connexion, de l'exécution de requêtes et de la gestion des résultats. Votre code sera ainsi plus propre, plus maintenable et plus flexible aux évolutions futures.
Il est généralement de bonne pratique d’écrire un DAO par table de la base de données. Dans le cadre de la gestion des animaux et des notes, l’application PETiSoin interagit avec deux tables :Animal
etNote
. Deux DAO seront donc nécessaires.
Débutons par le DAO lié à la tableAnimal
. L'implémentation technique d'un DAO, en Java ou Kotlin, consiste à définir une interface qui spécifie les méthodes pour accéder aux données. Vous devez donc créer une interfaceAnimalDao
.
Si vous utilisez Java : | Si vous utilisez Kotlin : |
|
|
Déclarez la méthode abstraite permettant de récupérer un animal
Pour chacune des opérations liées à la tableAnimal
, il est nécessaire de créer une méthode dans l’interface en réfléchissant à sa signature avec :
Le type de données retourné par la fonction ;
Les arguments nécessaires au bon fonctionnement de la fonction ;
Un nom explicite.
Créons ensemble la signature de la méthode qui permet de lire les informations d’un animal.
Le type de retour est ici évident : une instance de la classe
Animal
.Pour récupérer les informations d’un animal, la fonction doit savoir de quel animal elle doit récupérer les informations. Elle a donc besoin de pouvoir identifier de manière unique l’animal concerné par l’opération. Pour ça, rien de mieux que l’identifiant de l’animal qui est la clé primaire de la table
Animal
et qui par définition est donc unique.Finalement, pour le nom de la fonction, on utilise souvent la convention de nommage suivante :
{operation}{Type de retour}By{Argument}.
Pour le nom de l’opération, on utilise généralement les conventions de nommage suivantes :
get pour accéder à une ressource ;
delete pour supprimer une ressource ;
add pour ajouter une ressource ;
update pour mettre à jour une ressource.
Dans le cadre de notre exemple, la méthode s’appellera donc :getAnimalById
. Il est alors possible de compléter votre interface.
Si vous utilisez Java : | Si vous utilisez Kotlin : L'utilisation du mot-clé |
|
|
Déclarez la méthode abstraite permettant de récupérer l'ensemble des animaux
Avant de vous donner la solution pour les opérations suivantes, faisons le même exercice pour l’opération dont l’objectif est de récupérer l’ensemble des animaux de la base de données.
Le type de retour sera une collection.
Pour récupérer l’ensemble des animaux, la fonction associée n’a pas besoin d’argument car cette méthode doit retourner l’ensemble des animaux.
Si l’on adapte la convention de nommage décrit plus haut, on obtient comme nom :
getAllAnimals
.
Il est ainsi possible de compléter l’interfaceAnimalDao
.
Si vous utilisez Java : | Si vous utilisez Kotlin : |
|
|
Émettez des données en continu à partir de la base de données
Avant de passer à l’implémentation Java et Kotlin des autres opérations, attardons-nous sur la fonction getAllAnimals
que nous venons d’écrire. Imaginons que cette fonction est consommée dans l’écran principal de l’application. Au démarrage de l’application, l’ensemble des animaux présents dans la base de données s’affiche à l’écran. Imaginons maintenant que l’utilisateur ouvre un second écran pour ajouter un nouvel animal puis revienne sur l’écran principal : que se passera-t-il ?
La réponse dépend bien évidemment de ce qui a été implémenté. Mais en général le chargement des données se fait dans la méthode onCreate
de l’activité. Aussi, en retournant à l’écran principal, rien ne se passe. La liste des animaux reste la même. Le nouvel animal, fraîchement ajouté dans la base de données, n'apparaît pas. Ceci est dû au fait que la fonctiongetAllAnimals
ne renvoie le résultat qu’une seule fois, même si les données sous-jacentes (ajout d’un animal) sont modifiées.
Il est bien évidemment possible de trouver des solutions plus ou moins complexes comme rafraîchir les données au passage dans la méthode onResume
ou renvoyer un résultat entre les deux écrans en jouant avec lesIntent
. Mais si je vous disais que Room a tout prévu ?
En effet, pour résoudre ce problème, Room supporte une fonctionnalité qui permet aux DAO d’émettre des données en continu à partir de la base de données. Aussi, si un élément (dans notre cas un animal) est inséré, modifié ou supprimé, la fonction renverra automatiquement un nouveau résultat.
Pour bénéficier de cette fonctionnalité, il convient de changer le type de retour de la fonction. Plutôt que de renvoyer une collection, vous pouvez demander à votre fonction de renvoyer :
Une
LiveData
si vous utilisez le langage de programmation Java ;Un
Flow
si vous utilisez le langage de programmation Kotlin.
Si vous utilisez Java : En appliquant le type de retour | Si vous utilisez Kotlin : En appliquant le type de retour Flow à la méthode |
|
|
Déclarez la méthode abstraite permettant de récupérer le reste des opérations
Maintenant que l’exercice est compris, vous pouvez terminer l’écriture du DAO AnimalDao
avec les opérations manquantes et écrire le DAO NoteDao
.
Si vous utilisez Java : | Si vous utilisez Kotlin : |
|
|
À vous de jouer !
Contexte
Vous devez continuer l’implémentation technique de la rubrique “Santé” de l’application PETiSoin, en définissant des interfaces DAOs.
Dans le projet, disponible sur GitHub (Java ou Kotlin), une première interface DAOAnimalDao
a déjà été créée mais ce n’est pas suffisant pour permettre le bon fonctionnement de la rubrique “Santé” de l’application.
Consignes
Dans le packagecom.openclassRooms.Room.data.dao
, vous devez ajouter l’interface DAO VaccineDao
avec les méthodes qui permettent les opérations suivantes dans la base de données :
Lister les vaccins d’un animal ;
Ajouter un vaccin ;
Modifier un vaccin ;
Supprimer un vaccin.
Livrables
Vous pouvez dupliquer le projet GitHub pour modifier le code source du projet et fournir un projet qui compile.
En résumé
Quand on manipule une base de données, il existe 4 opérations : CRUD (Create, Read, Update, Delete).
Un DAO est une interface contenant l'ensemble des méthodes décrivant les opérations possibles sur la base de données.
Pour émettre des données en continu, il est possible de retourner un type
LiveData
en Java et un typeFlow
en kotlin.
Vous avez défini les types d’opérations que vous avez besoin d’inclure dans votre base de données. Vous avez aussi découvert le patron de conception logiciel DAO permettant d’exposer l’ensemble des interactions possibles avec votre base de données. La prochaine étape est de rendre fonctionnels ces DAO grâce aux différentes annotations de Room.