Pergunta

Aqui está uma simplificação do meu banco de dados:

Table: Property
Fields: ID, Address

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

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

Depois temos outras tabelas que se relacionam com o Citar e Trabalho tabelas individualmente.

agora preciso adicionar um Mensagem tabela onde os usuários podem gravar mensagens telefônicas deixadas pelos clientes sobre Trabalhos e Cotações.

Eu poderia criar duas tabelas idênticas (Mensagem de citação e Mensagem de trabalho), mas isso viola o princípio DRY e parece confuso.

eu poderia criar um Mensagem mesa:

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

Mas isso me impede de usar restrições para reforçar minha integridade referencial.Também posso prever que isso criará problemas no lado do desenvolvimento usando Linq to SQL posteriormente.

Existe uma solução elegante para esse problema ou terei que hackear algo juntos?

Queimaduras

Foi útil?

Solução

Crie uma tabela Message, contendo um MessageId exclusivo e as diversas propriedades que você precisa armazenar para uma mensagem.

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

Crie duas tabelas de links – QuoteMessage e JobMessage.Eles conterão apenas dois campos cada, chaves estrangeiras para Cotação/Trabalho e Mensagem.

Table: QuoteMessage
Fields: QuoteId, MessageId

Table: JobMessage
Fields: JobId, MessageId

Dessa forma, você definiu as propriedades de dados de uma Mensagem em um único local (facilitando a extensão e a consulta em todas as mensagens), mas também possui a integridade referencial vinculando Cotações e Trabalhos a qualquer número de mensagens.Na verdade, tanto uma cotação quanto um trabalho podem estar ligados ao mesmo mensagem (não tenho certeza se isso é apropriado para o seu modelo de negócios, mas pelo menos o modelo de dados oferece essa opção).

Outras dicas

A única outra maneira que consigo pensar é ter uma tabela Message base, com um Id e um TypeId.Suas subtabelas (QuoteMessage e JobMessage) fazem referência à tabela base em MessageId e TypeId - mas também possuem CHECK CONSTRAINTS para impor apenas o MessageTypeId apropriado.

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

O que isso traz para você, em comparação com apenas uma tabela JobMesssage e QuoteMessage?Ele eleva uma Mensagem a um cidadão de primeira classe, para que você possa ler todas as Mensagens de uma única tabela.Em troca, o caminho de consulta de uma mensagem até sua cotação ou trabalho relevante leva mais 1 adesão.Depende do fluxo do seu aplicativo, se isso é uma boa troca ou não.

Quanto a duas tabelas idênticas que violam o DRY - eu não ficaria preso a isso.No design de banco de dados, trata-se menos de DRY e mais de normalização.Se as duas coisas que você está modelando têm os mesmos atributos (colunas), mas na verdade são coisas diferentes (tabelas) - então é razoável ter várias tabelas com esquemas semelhantes.Muito melhor do que o inverso de misturar coisas diferentes.

@queimaduras

A resposta de Ian (+1) está correta [Veja a nota].Usando uma tabela muitos para muitos QUOTEMESSAGE juntar-se QUOTE para MESSAGE é o modelo mais correto, mas deixará órfão MESSAGE registros.

Este é um daqueles cru casos em que um gatilho pode ser usado.No entanto, é necessário ter cautela para garantir que o único MESSAGE registro não pode ser associado a um QUOTE e um 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 para Ian, acho que há um erro de digitação na definição da tabela para JobMessage, onde as colunas devem estar JobId, MessageId (?).Eu editaria sua citação, mas posso levar alguns anos para ganhar esse nível de reputação!

Por que não ter apenas os campos QuoteId e JobId na tabela de mensagens?Ou uma mensagem deve ser referente a uma cotação ou a um trabalho, e não a ambos?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top