J'ai toujours appliqué des contraintes au niveau de la base de données en plus de mes modèles (ActiveRecord). Mais je me demandais si c'était vraiment nécessaire?
Un peu de fond
J'ai récemment dû tester à l'unité une méthode de génération automatique d'horodatage de base pour un modèle. Normalement, le test crée une instance du modèle et l'enregistre sans validation. Mais il existe d'autres champs obligatoires qui ne peuvent pas être annulés dans la définition de la table, ce qui signifie que je ne peux pas enregistrer l'instance même si j'ignore la validation ActiveRecord. Je pense donc que je devrais supprimer ces contraintes de la base de données elle-même et laisser l'ORM les gérer?
Avantages possibles si je saute les contraintes en db, imo -
- Peut modifier une règle de validation dans le modèle, sans avoir à migrer la base de données.
- Peut ignorer la validation lors des tests.
Désavantage possible?
S'il est possible que la validation ORM échoue ou soit contournée, cependant, la base de données ne vérifie pas les contraintes.
Qu'est-ce que tu penses?
EDIT Dans ce cas, j'utilise le framework Yii , qui génère le modèle à partir de la base de données, donc les règles de base de données sont également générées (bien que je puisse toujours les écrire moi-même après la génération).
la source
Réponses:
Votre principe directeur devrait être de ne pas vous répéter :
L'ORM est essentiellement une couche supplémentaire (ou un niveau si vous préférez), reposant confortablement entre votre application et votre (vos) stockage (s) de données. Vos contraintes doivent être en un seul endroit, et un seul endroit, que ce soit l'ORM ou le stockage de données, sinon assez tôt vous finirez par en conserver différentes versions. Vous ne voulez vraiment pas faire ça.
Cependant, dans la pratique, la plupart des ORM à moitié décents génèrent automatiquement une grande partie de vos modèles à partir de votre schéma de données. Bien qu'il y ait toujours duplication, les chances d'enfer de maintenance sont minimes puisque le code ORM dupliqué est généré suivant le même modèle à chaque fois. Il serait idéal de ne pas avoir de code en double, mais les contraintes générées automatiquement sont la prochaine meilleure chose.
De plus, avoir vos contraintes au même endroit ne signifie pas nécessairement que vous devriez avoir toutes vos contraintes au même endroit. Certaines, comme les contraintes d'intégrité référentielle, peuvent être plus adaptées au stockage de données (mais peuvent être perdues si vous passez à un autre stockage de données), et certaines, principalement celles qui concernent une logique métier complexe, conviennent mieux à votre ORM. Il serait préférable d'avoir toutes vos pommes dans le même panier, mais…
Les échecs
Vous mentionnez l'échec de l'ORM. Cela n'a absolument rien à voir avec votre question, votre application doit considérer l'ORM et le (s) stockage (s) de données comme une seule entité. S'il échoue, il échoue, contourner l'ORM pour parler directement au stockage de données n'est pas une bonne idée.
Contourner l'ORM pour autre chose
Ce n'est pas non plus une bonne idée. Cependant, cela peut se produire pour diverses raisons:
Parties héritées de l'application qui ont été créées avant l'introduction de l'ORM.
C'est difficile, et c'est exactement la situation à laquelle je fais face en ce moment , d'où ma répétition constante de «l'enfer de la maintenance». Soit vous continuez à maintenir les parties non ORM, soit vous les réécrivez pour utiliser l'ORM. La deuxième option pourrait avoir plus de sens au départ, mais c'est une décision qui est uniquement basée sur ce que font exactement ces parties de votre application et sur la valeur d'une réécriture complète à long terme.
Essayez de changer une clé dans une table MySQL de 2 * 10 ^ 8 lignes mal conçue (sans temps d'arrêt) et vous comprendrez d'où je viens.
Parties non héritées de l'application qui doivent absolument parler directement au stockage de données:
Encore plus délicat. Les ORM sont des outils sophistiqués, et ils s'occupent de presque tout, mais parfois ils gênent ou sont même absolument inutiles. Le mot à la mode (vraiment la phrase à la mode) est une non-correspondance d'impédance relationnelle-objet , il suffit de dire qu'il n'est techniquement pas possible pour votre ORM de faire tout ce que fait votre base de données relationnelle, et pour certaines choses qu'ils font, il y a une pénalité de performance significative.
commentaires
C'est là que l'ajout d'une couche supplémentaire serait extrêmement utile, et si nous parlons d'une application Web, j'irais avec une API REST. Une conception trop simpliste pour cela serait:
L'ORM se situerait entre l'API et les stockages de données, et tout ce qui se trouve derrière l'API (y compris celle-ci) serait considéré comme une entité unique issue des différentes applications.
la source
C'est en fait une question très difficile à répondre et j'ai trouvé que c'était un sujet très controversé.
Comme Yannis Rizos l'a souligné dans sa réponse, avoir la logique de contrainte à la fois dans la base de données et dans la couche ORM semblerait violer DRY, ce qui "peut conduire à des cauchemars de maintenance, une mauvaise factorisation et des contradictions logiques".
Toutefois, la suppression de la logique de contrainte de la base de données et sa conservation uniquement au niveau de la couche ORM ne fonctionnerait pas si vous rencontrez l'une des conditions suivantes:
Mises à jour manuelles de la base de données (elles semblent se produire dans toutes les entreprises)
Mises à jour de base de données à partir d'un autre système qui ne peut pas toujours partager facilement la logique de contrainte ORM (ex / un script Perl qui effectue des tâches de routine lorsque la couche ORM est implémentée dans Hibernate et utilisée par une application Java pour l'activité quotidienne)
Cela suggérerait que vous n'ajoutiez que la logique de contrainte à la base de données et que vous la supprimiez de votre couche ORM afin d'éviter une violation DRY. Cependant, cela peut entraîner des cas où le code d'application ne parvient pas à capturer le problème réel et à le transmettre à l'utilisateur (bien qu'en tant que développeur déboguant le problème, vous le puissiez très probablement). Cela peut ne pas être acceptable pour certains projets.
Votre dernière option est d' automatiser la création des contraintes dans l'ORM (et tout autre système) à partir des contraintes DB (ou, vraiment ... vice versa). Bien que vous finirez par vous retrouver avec deux ou plusieurs implémentations des contraintes, ce ne sera pas une violation du principe DRY comme décrit dans "The Pragmatic Programmer" car ils recommandent l'utilisation de la génération de code pour éviter les violations DRY. Bien sûr, ce n'est pas aussi simple que cela, car, par exemple, chaque modification d'une contrainte de base de données peut forcer une reconstruction et un redéploiement de toutes vos applications qui l'utilisent (ce qui n'est pas trivial pour automatiser).
En réalité, cela devrait être évalué au cas par cas . Je peux vous dire qu'à ce stade, j'ai été confronté à des regards vides lorsque je suggère de ne pas répéter la logique de contrainte.
la source
Je voudrais certainement ajouter des contraintes à la base de données comme option par défaut. En effet, pour une entreprise, les données sont primordiales et la qualité des données est primordiale. @Yannis Rizos a introduit le principe DRY dans la discussion. Un autre principe est la défense en profondeur. Pour les données, j'utiliserais ce principe.
J'ai travaillé dans de vraies entreprises où la base de données a créé des données il y a 30 ans. Il était et est toujours accessible par l'application COBOL et maintenant par une application .Net. Dans 10 ans, ce sera peut-être une application de vendeur, qui sait. Il y a eu une fusion et des millions de lignes de données ont été converties et migrées de l'autre société vers cette base de données à l'aide de SQL. Aucun ORM ne peut le faire. En fin de compte, les données restent, les applications changent, la façon dont les données sont générées change. Alors pourquoi ne pas réduire les risques de corruption de données?
la source
Je pense que vous faites les deux dans une certaine mesure.
Les principales contraintes devraient vivre dans l'ORM - les langages de programmation sont beaucoup plus flexibles, il est plus facile à tester et plus facile à modifier lorsque les exigences changent; pas besoin de vous soucier des correctifs DDL au moins. Et vous évitez généralement les problèmes de régression des données difficiles à tester.
Certaines contraintes très dures et rapides devraient également vivre dans la base de données. Je ne parle pas de noms non nullables, par exemple. Je parle de choses comme l'intégrité référentielle ou nécessitant des identifiants absolument cruciaux. Exigences structurelles pour que votre code n'ait pas besoin de traiter "et si la Commande a un produit inexistant".
la source
La base de données est IMO le seul endroit où DRY peut être violé, car si quelque chose contourne votre ORM et contient de mauvaises données, c'est tout. Jeu terminé. Avoir des données corrompues est le coup fatal.
la source