Projeto de banco de dados para dados polimórficos

5

Eu tenho um aplicativo que precisa registrar as comunicações com os usuários em vários meios diferentes: E-mail, SMS, Voz, Anúncios do Site, etc. em um banco de dados tradicional.

Eu considerei três abordagens para modelar esses diferentes tipos de dados:

  1. Herança de uma única tabela link
    Armazene-os todos juntos em uma única tabela (ou seja, comm_message) com um campo discriminador de algum tipo para indicar o tipo de comunicação (por exemplo, message_type). Isso significa que alguns campos na tabela não serão usados para cada tipo - e isso significa que a mesma mensagem pode ser duplicada em várias linhas diferentes na tabela (se a mensagem for enviada por meio de mais de uma mídia).

  2. A mensagem "tem" transportes Ter uma tabela de mensagens (comm_message) e, em seguida, transporta a tabela (comm_transports) com os vários meios de comunicação diferentes. Um relacionamento muitos-para-muitos entre mensagens e transportes significaria uma linha para cada mensagem na tabela de mensagens, mas essa linha pode ter vários transportes diferentes. Se informações específicas adicionais forem necessárias para um transporte específico, elas podem estar em sua própria tabela (por exemplo, comm_sms, comm_email, etc.) que está vinculada à tabela muitos-para-muitos. Ou seja, uma abordagem "has-a".

  3. Herança da tabela de classes link Crie uma tabela de mensagens base (comm_message) e, em seguida, outra tabela para cada mídia com campos específicos para ela (herança). Meu ORM (LLBLGen) facilitaria essa abordagem usando PKs compartilhados para as diferentes tabelas. Nesta abordagem, haveria uma linha na tabela base (comm_message), além de linhas em cada uma das tabelas relacionadas para cada transporte (comm_email, comm_sms, etc.), mas não haveria relação muitos para muitos. Em vez disso, os registros em diferentes tabelas compartilhariam o mesmo PK (1-1). Isso seria mais uma abordagem "é-um".

Contexto: Este é um aplicativo de tamanho médio (cerca de 100 tabelas) que eu manteria por muitos anos - então eu gostaria de ter isso "certo". Frequentemente precisarei apresentar todas as informações de comunicação juntas na interface do usuário em uma grade, relatórios, etc.

Qual devo usar? Por quê?

    
por scotru 30.11.2014 / 10:57
fonte

2 respostas

3

Seguir composição sobre herança como composição se presta bem a bancos de dados relacionais .

Digamos que você queira receber todas as mensagens curtas:

SELECT * FROM Message INNER JOIN ShortMessage ON ShortMessage.message = Message.id

Digamos que você queira receber todas as mensagens curtas e e-mails:

SELECT * FROM Message 
   LEFT OUTER JOIN ShortMessage ON ShortMessage.message = Message.id 
   LEFT OUTER JOIN Email ON Email.message = Message.id

Isso efetivamente criará um conjunto de resultados muito parecido com a sua primeira opção, com muitos campos nulos.

Portanto, a ideia básica aqui é que uma mensagem potencialmente tem um e-mail . Dependendo de você definir ou não Email.message como UNIQUE , você pode verificar se há no máximo um e-mail correspondente a uma mensagem. Esta configuração (como todas as alternativas que você propôs) permite que uma única mensagem tenha múltiplos transportes diferentes, o que é realmente concebível no mundo real.

Vantagens dessa abordagem:

  • (acima de 1 e 2) Seu banco de dados está normalizado, o que geralmente fornece coisas de graça
    • se você quiser adicionar novos tipos de transporte sem alterar as tabelas existentes (não é algo que você deseja fazer em um banco de dados enorme)
    • Você não precisa armazenar cargas de nulos
  • (mais de 3) Você pode consultar todas as mensagens em uma consulta, assim você pode obter todas as mensagens para um destinatário específico, assim:

    SELECT IFNULL(Email.body, ShortMessage.body) as text FROM Message 
      LEFT OUTER JOIN ShortMessage ON ShortMessage.message = Message.id 
      LEFT OUTER JOIN Email ON Email.message = Message.id
      WHERE 
        Email.recepient = "[email protected]" 
        OR ShortMessage.recipient = "01189998819991197253"
    

    E voilà, você tem uma lista de todos os textos enviados para john doe.

No entanto, se você estiver usando um ORM, poderá usar o poder para realizar consultas como essa. Eu não tenho nenhuma experiência prática com c #, mas do meu entendimento como um estranho, Linq se presta bem a acessando bancos de dados relacionais para o que eles são , em vez de tentar encaixar a semântica de objetos em registros (o que sempre faz você atingir uma parede muito espessa em algum ponto da estrada).

    
por 30.11.2014 / 12:48
fonte
-1

Outra opção é usar um banco de dados que suporte nativamente a herança, por exemplo, PostgreSQL .

    
por 02.12.2014 / 12:14
fonte