Citation:
Envoyé par
plemaire
Je ne parlerais que des historiques pour ne citer qu’un seul cas.
Citation:
Envoyé par
plemaire
C’est comme pour une BDD, on ne peut dénormaliser que si on est capable de normaliser 5 d’abord, et ensuite d’expliquer la dénormalisation.
Et je dirai même plus : dans le cas de l'historisation des données, si vous ne normalisez pas en sixième forme normale et ne respectez pas les "Nine Requirements" associés, vous risquez tous les dangers et vous vous embarquez en tout cas dans des développements fort compliqués. Je vous renvoie à ce sujet à l'ouvrage de référence de Lorentzos, Darwen et Date, qui traitent du sujet en 400 pages (Temporal Data and the Relational Model).
Citation:
Envoyé par
plemaire
Et je le répète, la cohérence « technique » n’est pas forcement la meilleure, de plus elle représente BEAUCOUP moins de complexité que la cohérence fonctionnelle.
Un exemple simple : Avoir une entête de commande sans ligne ne pose aucun problème de contrainte, mais peut être catastrophique pour le fonctionnel, et là vos contraintes ne servent à rien !
Je suppose que par cohérence technique, vous voulez parler de la cohérence assurée par le SGBD. Je suppose encore que par « moins de complexité » vous voulez dire que les contraintes déclarées par exemple par CREATE ASSERTION, ne sont pas capables d'exprimer les contraintes fonctionnelles, c'est-à-dire l’ensemble des règles de gestion des données.
Mais l'objet est bien de sous-traiter ces règles de gestion au SGBD. Pour reprendre l’exemple que vous donnez, dans un premier temps, c’est au niveau du MCD (ou du diagramme de classe UML) que vous exprimez la règle qui veut qu’une commande comporte au moins une ligne de commande : à cet effet, la patte connectant l’entité-type Commande et l’association-type B est porteuse d’une cardinalité minimale 1.
http://www.fsmwarden.com/developpez/..._Commande).jpg
Pour exprimer ceci dans le cadre de la théorie relationnelle, vous définissez la contrainte traduisant cette cardinalité minimale :
CONSTRAINT CommandeConst1 IS_NOT_EMPTY (Commande JOIN LigneCommande) ;
Il est clair que cette contrainte remplace un bon paquet de lignes de code. Du point de vue des opérations, aucun problème, toujours dans le cadre de la théorie relationnelle, les contrôles sont déclenchés à des frontières d’instructions (statement boundaries), c'est-à-dire que vous pouvez empaqueter des INSERT (et autres instructions) que l’on les délimite par des virgules, tandis que les contrôles ne sont déclenchés qu’à la détection d’un point virgule, marquant la fin d’un paquet :
Code:
1 2 3 4 5 6 7 8 9 10
|
INSERT Commande RELATION {Tuple {CommandeId CommandeId 3,
CommandeDate Date "2010-01-06",
ClientId ClientId 123,
... }} , /* virgule : séparateur d’opérations */
INSERT LigneCommande RELATION {Tuple {CommandeId CommandeId 3,
LigneCdeId Integer 1,
ProduitId ProduitId 314
... Quantite Quantite 12
}} ; /* point-virgule : fin de liste */ |
Si l’on, passe à SQL, vous pouvez utiliser l’instruction CREATE ASSERTION, par exemple :
Code:
1 2 3 4 5 6 7
| CREATE ASSERTION CommandeConst1 CHECK(NOT EXISTS
(SELECT *
FROM Commande As X
WHERE NOT EXISTS (SELECT *
FROM LigneCommande As Y
WHERE X.CommandeId = Y.CommandeId) ) )
DEFERRABLE INITIALLY DEFERRED ; |
Toutefois, cette façon de procéder est nettement moins satisfaisante car, comme en SQL on ne peut pas empaqueter les INSERT et autres, on est conduit à utiliser la clause DEFERRABLE et déclencher les contrôles au moyen de l’instruction SET CONSTRAINTS ALL IMMEDIATE une fois créée une première ligne de commande (à défaut, d’attendre le prochain COMMIT).
Une solution plus intéressante consiste à imposer la création simultanée d’une commande et d’une première ligne de commande, ce qui conduit à créer une vue à cet effet, ainsi que le trigger chargé de ventiler les données (au cas où le SGBD ne sait pas encore le faire tout seul) :
Code:
1 2 3 4
| CREATE VIEW CommandeV (CommandeId, CommandeDate, ClientId, LigneCommandeId, ProduitId, Quantite) AS
SELECT x.CommandeId, x.CommandeDate, x.ClientId, y.LigneCommandeId, y.ProduitId, y.Quantite
FROM Commande AS x INNER JOIN LigneCommande AS y
ON x.CommandeId = y.CommandeId ; |
Puis, avec SQL Server :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13
| CREATE TRIGGER CommandeInsert ON CommandeV INSTEAD OF INSERT AS
INSERT INTO Commande
SELECT CommandeId
, CommandeDate
, ClientId
FROM INSERTED ;
INSERT INTO LigneCommande
SELECT CommandeId
, LigneCommandeId
, ProduitId
, Quantite
FROM INSERTED ; |
Et bien entendu, il faut prévoir le cas où à force de supprimer des lignes de commande, on pourrait se retrouver avec une commande sans aucune ligne :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| CREATE TRIGGER LigneCommandeDelete ON LigneCommande AFTER DELETE AS
SELECT ''
FROM Commande AS x, DELETED AS y
WHERE x.CommandeId = y.CommandeId
AND NOT EXISTS (SELECT *
FROM LigneCommande AS z
WHERE x.CommandeId = z.CommandeId)
IF @@Rowcount > 0
BEGIN
INSERT INTO LigneCommande
SELECT * from deleted ;
Raiserror ('Delete ligne facture : une commande ne peut pas rester sans ligne',16,1)
RETURN
END |
Tout cela est-il compliqué ? Pour prendre un autre exemple, si une règle de gestion des données stipule que le montant total des salaires des employés des départements de l’entreprise ne doit pas dépasser tel pourcentage par rapport au budget des départements, rien de plus simple à garantir dans le cadre du Modèle Relationnel de Données, c'est-à-dire de la théorie relationnelle. Même chose si l’on utilise une assertion SQL. En revanche, si l’on utilise un trigger SQL ou du code applicatif, on devra faire des tests exhaustifs pour s’assurer qu’on ne laissera pas passer le cas auquel on n’aura pas pensé tout de suite.
Cela dit, si les programmes que vous développez doivent « tourner » sur plusieurs SGBD, je conviens qu’il est agaçant de devoir modifier le codage des triggers parce que la syntaxe peut hélas varier d’un SGBD à l’autre. Mais concernant l’intégrité d’entité (définition des clés primaires et alternatives), ainsi que l’intégrité référentielle, un changement de SGBD ne devrait pas poser de problème et une fois de plus, il faut la mettre en oeuvre.
Citation:
Envoyé par
plemaire
La BDD est un outil GENERALISTE, qu'il convient d'utiliser à bon escient dans une application SPECIFIQUE. et si cela imlpique de NE PAS utiliser les FK, je ne vois pas en quoi cela choque. Et je ne comprend pas non plus, comment sans connaitre le besoin fonctionnel et Technique, on peut être aussi catégorique.
Une base de données n’est pas un outil. C’est une collection de données persistantes utilisées par les applications dans les entreprises.
Une donnée est persistante quand, une fois que le SGBD a validé son entrée dans la base de données, elle n’en sera retirée qu’au moyen d’une requête explicite faite au SGBD, par qui de droit.
A leur tour, le SGBD (disons relationnel) fournit le langage pour :
— Décrire la structure des données, sous forme de types et de variables relationnelles (ou de tables dans le cas de SQL) ;
— Affecter des valeurs de relations à ces variables (à cet effet, INSERT, UPDATE et DELETE sont des raccourcis pratiques, mais seulement des raccourcis) ;
— Dériver des valeurs de relations à partir d’autres valeurs de relations, au moyen d’opérateurs génériques (liste non limitée), qui constituent l’algèbre relationnelle (UNION, JOINTURE, RESTRICTION, PROJECTION, INTERSECTION, etc.)
— Garantir l’intégrité des données.
Ceci pour la partie fondamentale. Bien sûr, le SGBD doit fournir tout ce qui est nécessaire pour permettre les reprises sur incident, c'est-à-dire faire en sorte que les données restent dans un état cohérent quoi qu’il advienne, pour permettre la concurrence des accès à la base des données (mécanisme de verrouillage), pour assurer la sécurité des données, etc.
Quel que soit le support sur le quel reposent des données persistantes (y-compris sous forme de cartes perforées de la mécanographie des années cinquante, soixante), leur perte est irréparable. Souvenez-vous de l’incendie dans lequel Publicis a perdu ses données sauf, fort heureusement, le cœur de celles-ci. La leçon a été retenue par les autres entreprises et les sites de backup ont poussé comme des champignons. Mais ceci est une autre histoire.