Progettazione di database per dati polimorfici

5

Ho un'applicazione che ha bisogno di registrare le comunicazioni con gli utenti su diversi supporti: e-mail, SMS, voce, annunci sul sito web, ecc. in un database tradizionale.

Ho preso in considerazione 3 approcci per modellare questi diversi tipi di dati:

  1. ereditarietà di una tabella link
    Memorizzali tutti insieme in una singola tabella (cioè comm_message) con un campo discriminatore di qualche tipo per indicare il tipo di comunicazione (ad esempio, message_type). Ciò significa che alcuni campi della tabella non verranno utilizzati per ciascun tipo e significa che lo stesso messaggio può essere duplicato in diverse righe della tabella (se il messaggio viene inviato tramite più di un mezzo).

  2. Il messaggio "ha" i trasporti Avere una tabella dei messaggi (comm_message) e quindi trasporta la tabella (comm_transports) con i vari mezzi di comunicazione diversi. Una relazione molti-a-molti tra messaggi e trasporti significherebbe una riga per ogni messaggio nella tabella dei messaggi, ma quella riga potrebbe avere diversi trasporti diversi. Se sono necessarie informazioni specifiche aggiuntive per un particolare trasporto, potrebbe trovarsi nella propria tabella (ad es. Comm_sms, comm_email, ecc.) Che è collegata alla tabella many-to-many. Vale a dire, un approccio "ha-a".

  3. Ereditarietà della tabella delle classi link Creare una tabella di messaggi di base (comm_message) e quindi un'altra tabella per ciascun supporto con campi specifici (eredità). My ORM (LLBLGen) faciliterebbe questo approccio utilizzando PK condivisi per le diverse tabelle. In questo approccio ci sarebbe una riga nella tabella di base (comm_message), più le righe in ciascuna delle tabelle correlate per ogni trasporto (comm_email, comm_sms, ecc.) Ma non ci sarebbe alcuna relazione molti-a-molti. Piuttosto, i record su tabelle diverse condividono lo stesso PK (1-1). Questo sarebbe più di un approccio "è un".

Contesto: questa è un'applicazione di medie dimensioni (circa 100 tavoli) che conserverò per molti anni, quindi mi piacerebbe ottenere questo "giusto". Avrò spesso bisogno di presentare tutte le informazioni di comunicazione insieme nell'interfaccia utente in una griglia, rapporti, ecc.

Quale dovrei usare? Perché?

    
posta scotru 30.11.2014 - 10:57
fonte

2 risposte

3

Segui composizione sull'ereditarietà in quanto la composizione si presta bene ai database relazionali .

Supponiamo di voler ottenere tutti i messaggi brevi:

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

Supponiamo di voler ricevere tutti i messaggi e le email brevi:

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

Ciò creerà efficacemente un set di risultati molto simile a quello che è la prima opzione, con molti campi null.

Quindi l'idea di base qui è che un messaggio potenzialmente ha una email. A seconda che tu definisca o meno Email.message come UNIQUE , puoi assicurarti che al massimo una e-mail corrisponda a un messaggio. Questa configurazione (come tutte le alternative che hai proposto) consente a un singolo messaggio di avere più trasporti diversi, il che è effettivamente concepibile nel mondo reale.

Vantaggi di questo approccio:

  • (oltre 1 & 2) Il tuo database è normalizzato, che di solito ti dà roba gratis
    • se vuoi aggiungere nuovi tipi di trasporto senza alterare alcuna tabella esistente (non qualcosa che vuoi fare in un enorme database)
    • Non devi memorizzare un sacco di null
  • (oltre 3) Puoi interrogare tutti i messaggi in una query, in modo da poter ottenere tutti i messaggi a un destinatario specifico in questo modo:

    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à, ti sei procurato un elenco di tutto il testo inviato a john doe.

Tuttavia, se si sta utilizzando un ORM, è possibile utilizzare effettivamente la potenza per eseguire query del genere. Non ho esperienza pratica con C #, ma dalla mia comprensione come outsider, Linq si presta bene a accedere ai database relazionali per quello che sono , invece di cercare di adattare la semantica degli oggetti ai record (il che ti fa sempre colpire un muro molto spesso in qualche punto lungo la strada).

    
risposta data 30.11.2014 - 12:48
fonte
-1

Un'altra opzione è utilizzare un database che supporta in modo nativo l'ereditarietà, ad es. PostgreSQL .

    
risposta data 02.12.2014 - 12:14
fonte

Leggi altre domande sui tag