Domanda

Ecco una semplificazione del mio database:

Table: Property
Fields: ID, Address

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

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

Poi abbiamo altre tabelle che si riferiscono a Citazione E Lavoro tavoli individualmente.

Ora devo aggiungere a Messaggio tabella dove gli utenti possono registrare i messaggi telefonici lasciati dai clienti riguardanti Lavori e Preventivi.

Potrei creare due tabelle identiche (QuoteMessage E JobMessage), ma questo viola il principio DRY e sembra confuso.

Potrei crearne uno Messaggio tavolo:

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

Ma questo mi impedisce di utilizzare vincoli per rafforzare la mia integrità referenziale.Posso anche prevedere che creerà problemi con il lato sviluppo utilizzando Linq to SQL in seguito.

Esiste una soluzione elegante a questo problema o alla fine dovrò hackerare qualcosa insieme?

Brucia

È stato utile?

Soluzione

Crea una tabella Message contenente un MessageId univoco e le varie proprietà che devi archiviare per un messaggio.

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

Crea due tabelle di collegamento: QuoteMessage e JobMessage.Questi conterranno solo due campi ciascuno, chiavi esterne per Preventivo/Lavoro e Messaggio.

Table: QuoteMessage
Fields: QuoteId, MessageId

Table: JobMessage
Fields: JobId, MessageId

In questo modo hai definito le proprietà dei dati di un messaggio in un solo posto (rendendone facile l'estensione e l'esecuzione di query su tutti i messaggi), ma hai anche l'integrità referenziale che collega citazioni e lavori a un numero qualsiasi di messaggi.In effetti, sia una citazione che un lavoro potrebbero essere collegati a Stesso messaggio (non sono sicuro che sia appropriato per il tuo modello di business, ma almeno il modello di dati ti dà la possibilità).

Altri suggerimenti

L'unico altro modo che mi viene in mente è avere una tabella Message di base, con sia un Id che un TypeId.Le tue sottotabelle (QuoteMessage e JobMessage) fanno quindi riferimento alla tabella di base sia su MessageId che su TypeId, ma hanno anche CHECK CONSTRAINTS su di esse per applicare solo il MessageTypeId appropriato.

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

Cosa ti offre questo rispetto alle sole tabelle JobMessage e QuoteMessage?Eleva un Messaggio a cittadino di prima classe, in modo che tu possa leggere tutti i Messaggi da un'unica tabella.In cambio, il percorso della tua query da un messaggio al suo preventivo o lavoro pertinente è a 1 ulteriore iscrizione.Dipende dal flusso della tua app se si tratta di un buon compromesso o meno.

Per quanto riguarda 2 tabelle identiche che violano DRY, non mi rimarrei bloccato.Nella progettazione DB, si tratta meno di DRY e più di normalizzazione.Se le 2 cose che stai modellando hanno gli stessi attributi (colonne), ma in realtà sono cose diverse (tabelle), allora è ragionevole avere più tabelle con schemi simili.Molto meglio del contrario di mettere insieme cose diverse.

@burns

La risposta di Ian (+1) è corretta [Vedi nota].Utilizzo di una tabella molti a molti QUOTEMESSAGE unirsi QUOTE A MESSAGE è il modello più corretto, ma lascerà orfano MESSAGE record.

Questo è uno di quelli raro casi in cui è possibile utilizzare un trigger.Tuttavia, è necessario prestare attenzione per garantire che l'unico MESSAGE il record non può essere associato ad entrambi a QUOTE e 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

Nota per Ian: penso che ci sia un errore di battitura nella definizione della tabella per JobMessage, dove dovrebbero essere le colonne JobId, MessageId (?).Modificherei la tua citazione, ma potrebbero volerci alcuni anni per ottenere quel livello di reputazione!

Perché non avere solo i campi QuoteId e JobId nella tabella dei messaggi?Oppure il messaggio deve riguardare un preventivo o un lavoro e non entrambi?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top