Come modellare e memorizzare un'entità che ha "uno o più" valori

7

Userò C # per progettare il modello da mantenere

Supponiamo di avere la seguente entità:

public class Episode {
     public int Id { get; set; }
     public string Title { get; set; }
     public string Image { get; set; }
}

Questa è un'entità molto semplice, che è facile da mappare a un modello relazionale.

Ma cosa succede se voglio che la mia entità Episode abbia una o più immagini?

Come potrei rappresentarlo?

Posso, ad esempio, creare questo modello di entità:

public class Episode {
    public int Id { get; set; }
    public string Title { get; set; }
    public ICollection<string> Images { get; set; }
}

Ma questo, non garantisce che io abbia almeno una immagine nella mia collezione.

Inoltre, come potrei progettare il modello relazionale per questa entità? Come posso rappresentare un'entità che ha una relazione "da 1 a molti" con una stringa?

Devo creare una tabella aggiuntiva solo per la memorizzazione di queste "stringhe"?

Apprezzerei molto ogni consiglio che potresti voler condividere e l'approccio migliore a questo problema

    
posta Matias Cicero 15.12.2014 - 20:30
fonte

3 risposte

2

Per prima cosa devi decidere se è sufficiente avere sicurezza di runtime sul numero di immagini o se desideri avere compiletime safety .

Sicurezza in runtime

Raggiungere la sicurezza runtime è abbastanza semplice. Tutto quello che devi fare è rimuovere il setter di default per Images e implementare un setter che esegue un controllo prima di salvare l'argomento ICollection<string> dato se la raccolta ha almeno un elemento. Assicurati anche che non ci sia modo di cambiare Images se non usando questo setter sicuro.

Lo svantaggio è, naturalmente, che si può provare a chiamare il setter con un elenco emtpy e il tuo IDE non ti mostrerà che fallirà in fase di runtime.

Sicurezza Compiletime

Per ottenere la sicurezza necessaria è necessario dedicare più impegno. Come hai riconosciuto, una raccolta lo rende in grado di non archiviare elementi. Questo appartiene al suo contratto e va benissimo. Comunque nel tuo caso, non lo vuoi. Pertanto, una raccolta non è del tipo corretto e devi creare il tuo tipo. La mia migliore idea è creare una classe che implementa le funzionalità specifiche dell'elenco e la deleghi a un elenco salvato internamente. Tuttavia, i metodi che potrebbero impostare l'elenco interno vuoto, devono essere intercettati per assicurarsi che l'elenco non sia mai vuoto. Nel costruttore devi quindi fare qualcosa di disordinato. Ha 2 parametri: T Head e ICollection<T> Rest (entrambi non devono essere nulli). Il Head e tutti gli elementi di Rest vengono quindi inseriti nell'elenco interlale. Quando il primo argomento T non è nullo, l'elenco interal non è vuoto e siccome intercetti tutti i metodi che modificano l'elenco, puoi assicurarti che non diventi mai una lista vuota.

Non è molto elegante, secondo me, perché non puoi creare questo tipo solo da una lista. Ma in cambio si ottiene la sicurezza compiletime, quindi tutti coloro che cercano di instanciare questo tipo di dati vuoti avranno l'IDE che si lamenterà perché non è possibile.

Informazioni sulla tua domanda aggiuntiva per la memorizzazione nel database: Sì, penso che l'unico modo è avere una tabella aggiuntiva per le stringhe di immagini perché è "da 1 a molti". Non c'è modo di aggirare questo a meno che tu non rinunci alla normalizzazione.

    
risposta data 15.12.2014 - 21:13
fonte
1

Nel codice:

  • Convalida nel setter che la raccolta abbia almeno un elemento e genera ed eccezione se non lo fa.

Nel database:

  • Crea una tabella episode_image . Quella tabella avrebbe una chiave esterna con la tabella image .
  • Purtroppo, non c'è modo di applicarlo per ogni riga della tabella genitore, c'è almeno una riga corrispondente nella tabella figlio. Solo il contrario è possibile. Immagina: se le chiavi esterne funzionassero in entrambi i modi, sarebbe impossibile inserire una riga in A perché la riga corrispondente in B non esiste, ma non potresti inserire la riga necessaria in B, perché non esiste una riga corrispondente in A. Questo tipo di vincoli sono possibili in un modello concettuale ma non in un database fisico.
risposta data 15.12.2014 - 22:10
fonte
0

Ci sono alcune opzioni:

  1. Basta usare un normale ICollection , documentare il fatto che deve essere non vuoto e far rispettare questo nel setter. Nel database, avresti una tabella episode_images . Questo non fornisce la sicurezza in fase di compilazione che stai cercando, ma a mio parere è l'unica opzione ragionevole.

  2. È possibile memorizzare un campo FirstImage e un campo OtherImages . Nel database, potresti avere una colonna first_image in episodes e una tabella other_episode_images . Non suggerirei questo approccio in quanto sarebbe scomodo lavorare con quell'API.

  3. Come ha detto @valenterry, potresti introdurre un nuovo tipo di raccolta non vuota, che potrebbe memorizzare FirstElement e OtherElements campi. Non suggerirei questo come i chiamanti non vorrebbero essere costretti a lavorare con un tipo di raccolta non standard.

Do I need to create an additional table just for storing these "strings"?

Se davvero non vuoi una tabella aggiuntiva, puoi memorizzare raccolte serializzate in una colonna di testo, come ["image1", "image2", "image3"] . Ma una tabella separata è più idiomatica, e funziona meglio se devi fare qualche analisi da una console SQL, come trovare l'episodio con la maggior parte delle immagini.

    
risposta data 15.12.2014 - 21:49
fonte

Leggi altre domande sui tag