Avancé – Relations : OneToOne, OneToMany, ManyToOne et ManyToMany

Nous allons aborder un chapître assez simple, où nous allons revenir plus en détail sur les relations. Pour cela, assurez-vous d’avoir bien compris les notions de relations et de contraintes. Si ce n’est pas le cas, vous pouvez consulter les articles qui en parlent :

Avant de commencer, précisons que le thème que nous allons traiter dans ce chapître sera présenté pour les relations binaires, mais qu’il peut également être étendu aux relations n-aires.

Préparons le terrain

Avant d’aborder plus en profondeur les relations, il vous faut apprendre une nouvelle notion. Rassurez-vous, celle-ci est simple à comprendre.

Savez-vous ce qu’on appelle l’axe d’une relation dans Generic System ?

Il s’agit du type situé à la position i de la relation, i étant le numéro de l’axe. Appliquons cela à notre relation bien connue VehicleColor.

L’axe 0 de VehicleColor est Vehicle puisqu’il est à la position 0 dans la relation.
L’axe 1 est quand à lui Color puisque situé à la position 1 de la relation.

Enfin, retenez bien 2 termes : la base désigne l’axe 0 d’une relation, les targets désignent les autres axes de la relation.
Ainsi, la target 1 est l’axe 1 de la relation, la target 2 désigne l’axe 2 de la relation, et ainsi de suite.

Les différents types de relation

Il existe 4 types de relation : OneToOne, OneToMany, ManyToOne, ManyToMany.
Nous allons voir chacune d’elles et utiliser pour cela la SingularConstraint.

Relation OneToOne

La relation OneToOne n’est pas la plus utilisée, mais ce n’est pas pour autant que vous ne devez pas la connaître.
Cette relation spécifie que la base est liée à une seule target et qu’inversement une target est liée à une seule base.
Dans notre exemple de Vehicle, cela signifierait qu’un Vehicle ne peut avoir qu’une seule Color et qu’une Color ne peut appartenir qu’à un seul Vehicle.
Voyons comment la mettre en place :

Pour faire une relation OneToOne, il suffit d’activer la SingularConstraint sur ses 2 axes :

Nous pouvons ensuite déclarer le lien entre myVehicle et red :

Une fois un lien établi, toute tentative de création d’un nouveau lien (sur base ou target) sera rejetée par le système car un lien existe déjà.

Continuons sur notre lancée avec les relations ManyToOne.

Relation ManyToOne

La relation ManyToOne est certainement la plus utilisée. Si vous repensez aux bases de données relationnelles, la plupart des relations que vous avez rencontrées étaient des relations ManyToOne. Cette relation spécifie que la base est liée à une seule target et qu’une target peut être liée à plusieurs bases.
Dans notre exemple de Vehicle, cela signifierait qu’un Vehicle ne peut avoir qu’une seule Color et qu’une Color peut appartenir à plusieurs Vehicle.
Voyons comment mettre en place ce type de relation :

Pour faire une relation ManyToOne, il suffit d’activer la SingularConstraint sur la base uniquement, c’est-à-dire sur l’axe 0 :

Il suffit ensuite de créer le lien entre myVehicle et red :

Une fois un lien établi, il devient impossible d’ajouter un nouveau à la base puisqu’un lien existe déjà. Par contre, vous pouvez en rajouter autant que vous voulez à la target :

Continuons sur notre lancée avec les relations OneToMany qui sont très similaires.
En effet, il suffit de tourner la tête !

Relation OneToMany

La relation OneToMany étant l’exacte opposée de la ManyToOne, elle est tout aussi fréquente. Cette relation spécifie que la base peut être liée à plusieurs targets, mais qu’une target est liée à une seule base.
Dans notre exemple de Vehicle, cela signifierait qu’un Vehicle peut avoir plusieurs Color et qu’une Color ne peut appartenir qu’à un seul Vehicle.
Voyons comment mettre en place ce type de relation :

Pour faire une relation OneToMany, il suffit d’activer la SingularConstraint sur la target, c’est-à-dire sur l’axe 1 :

Il suffit ensuite de créer le lien entre myVehicle et red :

Une fois un lien établi, il est possible d’ajouter autant de lien que l’on souhaite à la base, mais il devient impossible d’ajouter un nouveau à la target puisqu’un lien existe déjà.

Voyons le dernier cas avec les relations ManyToMany.

Relation ManyToMany

Contrairement à ces consoeurs, la relation ManyToMany est très peu utilisée.
Cette relation spécifie que la base peut être liée à plusieurs targets et qu’une target peut être liée à plusieurs bases.
Dans notre exemple de Vehicle, cela signifierait qu’un Vehicle peut avoir plusieurs Color et qu’inversement une Color peut appartenir à plusieurs Vehicle.
Voyons comment mettre en place ce type de relation :

Puisque la SingularConstraint n’est pas activée par défaut dans Generic System, il n’y a rien à faire pour déclarer une relation ManyToMany ! On peut donc directement déclarer le lien entre myVehicle et red :

Une fois un lien établi, il est possible d’ajouter autant de lien que l’on souhaite à la base et et à la target, le système ne lèvera pas d’exception.

Terminons sur un point particulier à propos des relations ManyToMany.

Relations n-m et Snapshot

Reprenons notre exemple de notre relation ManyToMany VehicleColor :

Ajoutons maintenant des liens depuis la base ( myVehicle) et la target ( red) :

Il est alors facile de récupérer les liens créés, que ce soit depuis la base ( myVehicle) ou la target ( red) :

Jusque là, rien de bien nouveau. Mais nous allons maintenant aborder un point fort de Generic System par rapport aux bases de données relationnelles, plus particulièrement par rapport aux ORM.

Pour les ORM, la déclaration d’une relation ManyToMany impose de choisir une extrémité de la relation comme étant le maître, et l’autre l’esclave. Si des modifications sont apportées, elle ne peuvent se faire que sur le maître. De plus, si des lectures avaient été faites sur l’esclave avant ces modifications, elles ne seront plus actualisées.

Dans le cas de Generic System, il n’y a pas de maître ni d’esclave : les modifications peuvent être effectuées depuis la base ou la target, et chacune connaîtra les modifications effectuées. Generic System reste cohérent.

Ajoutons un lien à notre base myVehicle :

Lorsque l’on interroge le snapshot  linksFromTheBase, il contient bien les deux liens que nous avons créés depuis myVehicle :

Mais ce qui est plus intéressant, c’est que le nouveau lien apparaît également dans le snapshot  linksFromTheTarget :

Bien que le lien ait été créé à partir de la base, la target a bien été informée de la création.

Nous pouvons aussi vérifier que l’inverse est vrai. Commençons par supprimer le lien qu’on vient d’ajouter, et vérifions que sa suppression a bien été enregistrée :

Ajoutons alors des links depuis la target et récupérons-les depuis la target puis la base :

Nous pouvons ensuite vérifier que le lien apparaît bien dans nos deux  Snapshot :

En résumé

  • L’axe i d’une relation désigne le type à la position i de ladite relation.
  • L’axe 0 est appelée base, les autres axes étant appelés targets.
  • Il existe 4 types de relations : OneToOne, OneToMany, ManyToOne, ManyToMany.
    Toutes peuvent être mises en oeuvre en utilisant la SingularConstraint.
  • Les relations n-m peuvent être modifiées et lues depuis la base comme la target et chacune restera informée des modifications effectuées par l’autre.
  • Toutes les notions présentées ici concernaient les relations binaires.
    Elles peuvent bien évidemment être étendues aux relations n-aires.

Nous allons ensuite découvrir ensemble le fabuleux monde des Tree !