Question

Voici une simplification de ma base de données :

Table: Property
Fields: ID, Address

Table: Quote
Fields: ID, PropertyID, BespokeQuoteFields...

Table: Job
Fields: ID, PropertyID, BespokeJobFields...

Ensuite, nous avons d'autres tableaux qui concernent le Citation et Emploi tableaux individuellement.

Je dois maintenant ajouter un Message tableau où les utilisateurs peuvent enregistrer les messages téléphoniques laissés par les clients concernant les travaux et les devis.

Je pourrais créer deux tables identiques (Message de devis et Message de travail), mais cela viole le principe DRY et semble compliqué.

Je pourrais en créer un Message tableau:

Table: Message
Fields: ID, RelationID, RelationType, OtherFields...

Mais cela m'empêche d'utiliser des contraintes pour faire respecter mon intégrité référentielle.Je peux également prévoir que cela créera des problèmes avec le côté développement en utilisant Linq to SQL plus tard.

Existe-t-il une solution élégante à ce problème, ou vais-je finalement devoir pirater quelque chose ensemble ?

Brûlures

Était-ce utile?

La solution

Créez une table Message, contenant un MessageId unique et les différentes propriétés que vous devez stocker pour un message.

Table: Message
Fields: Id, TimeReceived, MessageDetails, WhateverElse...

Créez deux tables de liens - QuoteMessage et JobMessage.Ceux-ci contiendront simplement deux champs chacun, des clés étrangères du devis/travail et du message.

Table: QuoteMessage
Fields: QuoteId, MessageId

Table: JobMessage
Fields: JobId, MessageId

De cette façon, vous avez défini les propriétés de données d'un message en un seul endroit (ce qui facilite l'extension et l'interrogation de tous les messages), mais vous disposez également de l'intégrité référentielle reliant les devis et les tâches à un nombre quelconque de messages.En effet, un devis et un travail peuvent être liés au même message (je ne sais pas si cela est approprié à votre modèle commercial, mais au moins le modèle de données vous donne la possibilité).

Autres conseils

La seule autre façon à laquelle je peux penser est d'avoir une table Message de base, avec à la fois un Id et un TypeId.Vos sous-tables (QuoteMessage et JobMessage) font ensuite référence à la table de base sur MessageId et TypeId - mais ont également CHECK CONSTRAINTS sur elles pour appliquer uniquement le MessageTypeId approprié.

Table: Message
Fields: Id, MessageTypeId, Text, ...
Primary Key: Id, MessageTypeId
Unique: Id

Table: MessageType
Fields: Id, Name
Values: 1, "Quote" : 2, "Job"

Table: QuoteMessage
Fields: Id, MessageId, MessageTypeId, QuoteId
Constraints: MessageTypeId = 1
References: (MessageId, MessageTypeId) = (Message.Id, Message.MessageTypeId)
            QuoteId = Quote.QuoteId

Table: JobMessage
Fields: Id, MessageId, MessageTypeId, JobId
Constraints: MessageTypeId = 2
References: (MessageId, MessageTypeId) = (Message.Id, Message.MessageTypeId)
            JobId = Job.QuoteId

Qu'est-ce que cela vous rapporte, par rapport à une simple table JobMesssage et QuoteMessage ?Il élève un message au rang de citoyen de première classe, afin que vous puissiez lire tous les messages à partir d'une seule table.En échange, votre chemin de requête depuis un message vers son devis ou son travail pertinent est à 1 jointure supplémentaire.Cela dépend en quelque sorte du flux de votre application, que ce soit un bon compromis ou non.

Quant à 2 tables identiques violant DRY, je ne m'y accrocherais pas.Dans la conception de bases de données, il s'agit moins de DRY que de normalisation.Si les 2 éléments que vous modélisez ont les mêmes attributs (colonnes), mais sont en réalité des éléments différents (tables), alors il est raisonnable d'avoir plusieurs tables avec des schémas similaires.Bien mieux que l’inverse consistant à mélanger différentes choses ensemble.

@brûlures

La réponse de Ian (+1) est correcte [voir la note].Utiliser une table plusieurs à plusieurs QUOTEMESSAGE joindre QUOTE à MESSAGE est le modèle le plus correct, mais laissera orphelin MESSAGE enregistrements.

C'est un de ceux-là rare cas où un déclencheur peut être utilisé.Il convient toutefois de faire preuve de prudence pour garantir que le seul MESSAGE l'enregistrement ne peut pas être associé à la fois à un QUOTE et un JOB.

create trigger quotemessage_trg
on quotemessage
for delete
as
begin

delete 
from [message] 
where [message].[msg_id] in 
    (select [msg_id] from Deleted);

end

Note à Ian, je pense qu'il y a une faute de frappe dans la définition du tableau pour JobMessage, où les colonnes doivent être JobId, MessageId (?).Je modifierais bien votre citation mais cela pourrait me prendre quelques années pour acquérir ce niveau de réputation !

Pourquoi ne pas simplement avoir les champs QuoteId et JobId dans la table des messages ?Ou un message doit-il concerner soit un devis, soit un travail et non les deux ?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top