Skip to content

Data mapping (FR)

Thanh-Son-Philippe Lam edited this page Nov 30, 2018 · 3 revisions

Contexte

Le module Repository du projet contient la logique permettant de récupérer les données à partir de la base de données et du services web. Il agit en tant que médiateur entre différentes sources de données et retourne les données au client. Cela permet, entre autres, de centraliser la logique de récupération des données, d’éviter la duplication de code et d’améliorer la testabilité. Lors de la récupération des données, le module Repository effectue des opérations de mise en correspondance (mapping), c’est-à-dire qu’il transforme les données en différentes représentations afin que celles-ci puissent être utilisées par le client. Une exemple de transformation serait la conversion d'un attribut de date. Dans ce cas de figure, l'objet retourné par le service web contiendrait une date sous la forme d'une forme d'une chaîne de caractères spécifique. Afin que celle-ci puisse être utilisée par le client, elle doit préalablement être transformée. Cette transformation serait alors effectuée par un « mapper ».

Pourquoi « mapper »?

En plus de faciliter l'utilisation des données pour le client, il existe également d'autres raisons pour lesquelles on souhaiterait mapper.

Lorsqu’une donnée est récupérée à partir d’un service web, celle-ci est sous une représentation spécifique définie par le service web. Par la suite, celle-ci est convertie en POJO par Moshi. Pour ce faire, le modèle est une classe marquée par l’annotation JsonSerializable. De plus, les attributs peuvent être marqués par des annotations spécifiant leurs noms.

Ensuite, afin que cette donnée puisse être stockée dans la base de données à l’aide de la librairie Room, celle-ci doit être marquée par l’annotation Entity et munie d’un attribut défini en tant que clé primaire. Davantage d'annotations ont donc dû être insérées. Cela entraîne des problèmes tels que la complexification du modèle ainsi qu'un couplage entre la logique de sérialisation des données et la persistance des données. Par exemple, il se pourrait qu’après la récupération de données à partir du service web, qu’un nouvel attribut doive être introduit dans le modèle. Ce cas se présente lorsqu’on a demandé une donnée selon un attribut particulier et que le modèle retourné par le service web ne contient pas cet attribut. Après l’insertion de ce modèle dans la base de données, afin que celui-ci puisse être retrouvé par après, celui-ci doit avoir été préalablement muni du même attribut. Cependant, il ne suffit pas d'ajouter cet attribut à notre modèle, car Moshi ne pourrait pas convertir le résultat de la requête puisque celui-ci ne contiendrait pas cet attribut. Une solution serait d’utiliser l'annotation « Transient » afin de signaler à Moshi d’ignorer cet attribut. Cependant, cela empêcherait la sauvegarde dans la base de données, car Room ignorerait également cet attribut.

Un autre désavantage de l'utilisation d'un seul modèle est que la vue dépendrait également de la représentation fournie par le service web et utilisée pour la persistance. Cela signifie qu’un changement à la base de données ou au service web impacterait fortement celle-ci. Ce problème est encore plus important si la source n’est pas sous le contrôle des développeurs. Des exemples seraient un changement par rapport à l’API de Signets ou encore l'introduction de l'API de MonETS.

Bref, il serait préférable que le projet ait des modèles spécifiques pour le client, la base de données et le service web, et ce dans le but de réduire le couplage, minimiser les impacts des changements, etc.

Les modèles du projet

Utilisation Description Caractéristique Emplacement
Service web Représentations des données retournées par un service web Munies du préfixe « Api » response
Base de données Représentations des données stockées dans la base de données Munies du suffixe « Entity » entity
Client Représentations des données utilisées par le client Dénuées de suffixe ou de préfixe model

Les « mappers »

Les « mappers » du projet sont des extensions. Ceux-ci sont utilisés pour effectuer la conversion d'un modèle à un autre.

Actuellement, l'application utilise l'API de Signets et, généralement, les données retournées par celles-ci ne peuvent pas être directement stockées dans la base de données. Pour ce faire, elles doivent souvent être munies d'un ou plusieurs attributs supplémentaires. Les extensions s'occupant de cette tâche ont été placées dans le fichier SignetsApiMapperExt. Voici un exemple :

fun ApiSeance.toSeanceEntity(cours: Cours) = SeanceEntity(
        this.dateDebut,
        this.dateFin,
        this.nomActivite,
        this.local,
        this.descriptionActivite,
        this.libelleCours,
        cours.sigle,
        cours.session
)

Dans cet exemple, l'objet ApiSeance est recopié tel quel et muni du sigle et du cours de la session. Cela permettra, par après, de retrouver les séances selon un cours donné à partir de la base de données.

Ensuite, en ce qui concerne les entités de la base de données, les extensions placées dans le fichier SignetsDbMapperExt se chargent de les convertir vers des modèles qui pourront être utilisés par le client.

Références