Non, ce n'est pas OK. Les références circulaires entre les tables sont désordonnées. Consultez cet article (vieux de dix ans) :SQL By Design :The Circular Reference
Certains SGBD peuvent les gérer, et avec un soin particulier, mais MySQL aura des problèmes.
Option 1
En tant que conception, pour rendre l'un des deux FK nullable. Cela vous permet de résoudre le problème de la poule et de l'œuf (dans quel tableau dois-je d'abord insérer ?).
Il y a cependant un problème avec votre code. Cela permettra à un produit d'avoir une image par défaut où cette image fera référence à un autre produit !
Pour interdire une telle erreur, votre contrainte FK doit être :
CONSTRAINT FK_products_1
FOREIGN KEY (id, default_picture_id)
REFERENCES products_pictures (product_id, id)
ON DELETE RESTRICT --- the SET NULL options would
ON UPDATE RESTRICT --- lead to other issues
Cela nécessitera un UNIQUE
contrainte/index dans la table products_pictures
sur (product_id, id)
pour que le FK ci-dessus soit défini et fonctionne correctement.
Option 2
Une autre approche consiste à supprimer le Default_Picture_ID
colonne forme le product
table et ajoutez un IsDefault BIT
colonne dans l'picture
table. Le problème avec cette solution est de savoir comment permettre à une seule image par produit d'avoir ce bit et à tous les autres de l'avoir. Dans SQL-Server (et je pense dans Postgres), cela peut être fait avec un index partiel :
CREATE UNIQUE INDEX is_DefaultPicture
ON products_pictures (Product_ID)
WHERE IsDefault = 1 ;
Mais MySQL n'a pas une telle fonctionnalité.
Option 3
Cette approche vous permet même d'avoir les deux colonnes FK définies comme NOT NULL
est d'utiliser des contraintes reportables. Cela fonctionne dans PostgreSQL et je pense dans Oracle. Vérifiez cette question et la réponse de @Erwin :Contrainte de clé étrangère complexe dans SQLAlchemy
(le champ Toutes les colonnes clés NON NULLES partie).
Les contraintes dans MySQL ne peuvent pas être différées.
Option 4
L'approche (que je trouve la plus propre) consiste à supprimer le Default_Picture_ID
colonne et ajouter une autre table. Aucun chemin circulaire dans les contraintes FK et toutes les colonnes FK seront NOT NULL
avec cette solution :
product_default_picture
----------------------
product_id NOT NULL
default_picture_id NOT NULL
PRIMARY KEY (product_id)
FOREIGN KEY (product_id, default_picture_id)
REFERENCES products_pictures (product_id, id)
Cela nécessitera également un UNIQUE
contrainte/index dans la table products_pictures
sur (product_id, id)
comme dans la solution 1.
Pour résumer, avec MySQL, vous avez deux options :
-
option 1 (une colonne FK acceptant les valeurs nulles) avec la correction ci-dessus pour appliquer correctement l'intégrité
-
option 4 (aucune colonne FK acceptant les valeurs nulles)