Faire démarrer quelques projets avec EF, mais j'avais quelques questions sur les tables de jointure et les clés, etc. Disons que j'ai une table d'applications et une table d'autorisations. Les applications ont de nombreuses autorisations et chaque autorisation peut appartenir à de nombreuses applications (plusieurs à plusieurs).
Maintenant, les tables d'application et d'autorisation sont faciles:
Applications
--------------
PK ApplicationID
Name
Permissions
--------------
PK PermissionID
Name
Mais quelle est la MEILLEURE façon de faire la table de jointure? J'ai ces deux options:
ApplicationPermissions
-----------------------
PK ApplicationPermissionID
CU ApplicationID
CU PermissionID
OR
ApplicationPermissions
-----------------------
CPK ApplicationID
CPK PermissionID
PK = Primary Key
CPK = Composite Primary Key
CU = Composite Unique Index
Avez-vous déjà été brûlé en le faisant d'une manière par rapport à l'autre? est-ce strictement une préférence? Il m'est venu à l'esprit que beaucoup de "différences" seront résumées par mon modèle de référentiel (par exemple, je ne créerais presque jamais un objet d'autorisation entier et l'ajouterais à une application, mais le faire par ID ou nom unique ou quelque chose), mais je suppose que je cherche des histoires d'horreur, d'une manière ou d'une autre.
Je pense que vous voulez dire une table de "jonction", pas une table de "jointure".
Il n'est pas nécessaire qu'une table de jonction ait son propre champ ID. Vous n'auriez jamais besoin de rejoindre ou de filtrer sur un tel ID. Vous souhaitez uniquement joindre ou filtrer les ID des tables que vous mappez. Un ID sur une table de jonction est un gaspillage d'espace disque.
Donc, la "meilleure" option est d'éviter l'ID. En règle générale, une table de jonction aura 2 index de recouvrement. Chaque index de couverture utilisant l'un des ID mappés comme champ de tri principal.
Mais "le meilleur" n'est pas de loin. C'est un problème très mineur d'avoir un champ ID redondant. Vous n'aurez pas d'histoires d'horreur sur une petite quantité de disque gaspillé. L'ID ne "volera" pas l'index clusterisé car vous ne voulez de toute façon pas clusteriser sur le combo mappé.
Si votre framework veut que toutes les tables aient un ID, allez-y. Si les normes de base de données de votre équipe dictent que toutes les tables doivent avoir un ID, allez-y. Sinon, évitez-le.
Au fil des ans, j'ai pris l'habitude de donner à chaque table "TableName" une clé primaire générée automatiquement "TableNameID", sans aucune exception, pas même pour les tables de jonction. Je peux dire que je ne l'ai jamais regretté, car cela facilite beaucoup de choses lors de la création de code générique qui fait quelque chose pour "toutes les tables" ou "certaines tables", ou pour "beaucoup de lignes de plusieurs tables différentes".
Par exemple, si quelqu'un vous demande de stocker des lignes de tables différentes (ou des références à celles-ci) dans un fichier ou en mémoire, par exemple, à des fins de journalisation, il est très pratique lorsque vous savez au préalable que vous avez juste besoin d'en stocker exactement une nom de la table et exactement un ID entier, et vous n'avez pas à vous occuper de "cas spéciaux".
Une autre chose, lorsque vous commencez avec des PK combinés, vous rencontrerez probablement quelques fois plus tard le besoin de clés étrangères combinées (puisque vous pouvez arriver à un point où vous souhaitez ajouter une référence FK à votre table ApplicationPermissions
) . Ensuite, la prochaine exigence peut être d'avoir ce FK unique en conjonction avec d'autres attributs ou clés étrangères - ce qui entraînera une complexité globale accrue. Rien de ce qui n'est pas possible à gérer pour la plupart des systèmes DB modernes, bien sûr, mais une solution uniforme facilite souvent la vie des programmeurs.
Et enfin, une instruction comme SELECT ... FROM TABLE WHERE TableNameID IN (id1,id2,...)
fonctionne bien avec une seule colonne comme clé primaire, mais je n'ai jamais vu de dialecte SQL jusqu'à présent qui vous permet de le faire avec des clés combinées. Si vous savez à l'avance que vous n'aurez jamais besoin d'une requête comme celle-ci, très bien, mais ne soyez pas surpris si demain vous obtenez une exigence qui sera résolue plus facilement avec ce type de SQL.
Bien sûr, lorsque vous vous attendez à ce que votre table ApplicationPermissions
contienne plusieurs centaines de millions de lignes, alors vous devriez envisager d'éviter quelque chose comme un ApplicationPermissionsID
.
Bien que la réponse de Mike soit bonne, voici les raisons pour lesquelles j'ajouterais un champ ID distinct ou non.
Pensez à utiliser un champ d'ID distinct pour la table de jonction/jointure s'il contient des champs autres que l'ID. Cela tend à noter qu'il s'agit d'une entité de première classe.
Envisagez d'utiliser un champ ID distinct si les API ou toute logique existante ont tendance à utiliser des champs uniques pour récupérer/modifier des entités. Cela peut aider d'autres personnes à suivre votre code dans le cadre d'un projet plus vaste.
Ne l'utilisez pas s'il n'y a aucun avantage spécifique (KISS). EF sait comment gérer ce type de table et une contrainte composite unique peut parfois être manquée lorsque d'autres personnes tentent de comprendre ce type de relation. De plus, lors de la normalisation, j'essaie d'utiliser la plus petite clé possible qui définit uniquement le tuple. Dans votre deuxième exemple, vous avez effectivement 2 clés primaires candidates distinctes.