Capitolo 02
Generalizzazioni
All animals are equal, but some animals are more equal than others.
Nella lezione precedente studenti e professori erano due entità separate, ognuna con il suo nome e il suo identificatore. Le due entità hanno però molto in comune: nome e cognome, una bacchetta, un Patronus. Ogni volta che il dominio chiede qualcosa di nuovo su tutte le persone di Hogwarts, il modello deve scriverlo due volte, una per entità. In questa lezione raccogliamo ciò che studenti e professori hanno in comune in un’entità più generale, e vediamo che questa raccolta, comoda nel diagramma, si può trasformare in tabelle in tre modi, nessuno dei quali conserva tutto.
Due entità con le stesse proprietà
Immaginiamo che il database di Hogwarts debba registrare le bacchette di tutti, studenti e professori: anche Piton ha una bacchetta, come Harry. Con il modello che abbiamo servono due associazioni possiede, una fra studente e bacchetta e una fra professore e bacchetta, con le stesse cardinalità. Lo stesso vale per nome e cognome, che compaiono fra gli attributi di tutte e due le entità, e per il Patronus della lezione “Entità e attributi”, che hanno anche i professori: quello di Piton è una cerva.
Studenti e professori sono due casi particolari della stessa cosa, una persona che vive a Hogwarts. Il modello E/R lo esprime con una generalizzazione: un’entità persona, con gli attributi e le associazioni che tutte le persone hanno, e sotto di lei le entità studente e professore, ognuna con ciò che riguarda solo lei: l’anno per lo studente, la materia per il professore.
Se hai già scritto classi in Python, la generalizzazione ti ricorda l’ereditarietà fra classi, e il parallelo regge: la figlia ha tutto ciò che ha il padre, più qualcosa di suo. Come per entità e classi, nel modello E/R mancano i metodi.
Nel diagramma la generalizzazione è una freccia che va dalle entità figlie al padre. Accanto a persona, in possiede, il minimo è 0: a Hagrid la bacchetta l’hanno spezzata quando è stato espulso, e da allora la sua magia passa da un ombrello rosa. Gli attributi di studente e professore sono soltanto quelli propri: il nome, il codice e la bacchetta di uno studente stanno nel padre, e valgono per lui come per ogni altra persona.
La copertura
Accanto alla freccia il diagramma porta due lettere, (p,e). Sono la copertura della generalizzazione, e rispondono a due domande sul dominio, come le cardinalità.
La prima domanda: ogni persona registrata è per forza uno studente o un professore? Hagrid no. Nei primi due anni di Harry a Hogwarts è il guardiacaccia della scuola, e non è né uno studente né un professore. Se il database registra anche Hagrid, alcune persone non appartengono a nessuna entità figlia, e la generalizzazione è parziale, p. Se ogni persona registrata è per forza uno studente o un professore, è totale, t.
La seconda domanda: una persona può essere studente e professore insieme? Fra gli studenti e i professori di un anno scolastico, no: la generalizzazione è esclusiva, e. Immaginiamo però l’archivio della lezione sulle chiavi, con tutti gli studenti passati da Hogwarts. Piton e Lupin a Hogwarts hanno studiato, e anni dopo insegnato, senza essersi mai resi simpatici né agli studenti né ai professori: nell’archivio Piton è un’occorrenza di studente e anche di professore, e la generalizzazione è sovrapposta, o, dall’inglese overlapping.
Nell’archivio di tutti gli anni Piton e Hagrid sono stati studenti e poi professori: gli insiemi si sovrappongono.
- In un anno scolastico nessuno è studente e professore insieme, e Hagrid non è nessuno dei due.
- Nell’archivio di tutti gli anni Piton e Hagrid sono stati studenti e poi professori: gli insiemi si sovrappongono.
La copertura, come le cardinalità, non si ricava dai nomi delle entità. Le persone di Hogwarts sono le stesse, ma il database di un anno scolastico ha la copertura (p,e), e l’archivio di tutti gli anni (p,o). Nell’archivio anche Hagrid smette di essere un caso a parte: prima di diventare guardiacaccia è stato studente, fino all’espulsione al terzo anno, e dal terzo anno di Harry è anche professore, con un libro di testo che morde (al contrario di Python Doesn’t Byte).
Tre modi di farne tabelle
Le tabelle non hanno generalizzazioni: una tabella non ha figlie. Prima di trasformare il modello in tabelle, quindi, ogni generalizzazione va tolta, e i modi di toglierla sono tre. Le regole complete per passare dal modello alle tabelle arrivano nel capitolo 3; qui guardiamo soltanto che cosa perde ciascuno dei tre modi, sulle persone di Hogwarts.
Solo il padre
Le figlie spariscono dentro il padre. La tabella persona riceve le colonne di tutte le figlie, più una colonna tipo che dice a quale figlia appartiene ogni riga.
| codice | nome | cognome | tipo | anno | materia |
|---|---|---|---|---|---|
| 1 | Harry | Potter | studente | 1 | |
| 2 | Severus | Piton | professore | Pozioni | |
| 3 | Rubeus | Hagrid |
Hagrid ci sta, con il tipo vuoto, e l’associazione possiede resta una sola. Si perdono però le regole delle figlie: niente impedisce una riga di tipo studente con una materia, o uno studente senza anno. E un’associazione che riguarda solo gli studenti, come appartiene, diventa un’associazione di tutte le persone, professori compresi. Con la copertura sovrapposta, poi, una colonna tipo con un valore solo non sa dire che Piton è stato studente ed è professore.
Solo le figlie
Il padre sparisce, e ogni figlia riceve i suoi attributi: la tabella studente ha codice, nome, cognome e anno, la tabella professore codice, nome, cognome e materia.
| codice | nome | cognome | anno |
|---|---|---|---|
| 1 | Harry | Potter | 1 |
| codice | nome | cognome | materia |
|---|---|---|---|
| 2 | Severus | Piton | Pozioni |
Le regole delle figlie restano: uno studente ha un anno e non ha una materia. Si perde invece la persona. Hagrid, che non è né studente né professore, non ha una tabella in cui stare: una copertura parziale con questo modo non si può registrare. Nell’archivio, Piton compare in tutte e due le tabelle, con nome e cognome scritti due volte, ed è la ridondanza del capitolo 1. E l’associazione possiede va raddoppiata, una per tabella.
Padre e figlie, collegati
Restano tutte e tre le entità. La tabella persona ha codice, nome e cognome; la tabella studente ha il codice e l’anno, la tabella professore il codice e la materia, e il codice di ogni riga di una figlia indica una riga di persona.
| codice | nome | cognome |
|---|---|---|
| 1 | Harry | Potter |
| 2 | Severus | Piton |
| 3 | Rubeus | Hagrid |
| codice | anno |
|---|---|
| 1 | 1 |
| codice | materia |
|---|---|
| 2 | Pozioni |
Hagrid sta nella tabella persona e in nessuna figlia, Piton nell’archivio avrebbe una riga in persona e una in ciascuna figlia, e nome e cognome sono scritti una volta sola. Il prezzo sono gli incroci: per avere il nome e l’anno di uno studente servono due tabelle, unite come il DBMS unisce assegnazione e studente. E neanche questo modo fa rispettare la copertura: in una generalizzazione esclusiva, niente impedisce che lo stesso codice compaia in tutte e due le figlie.
| Modo | Conserva | Perde |
|---|---|---|
| solo il padre | le persone senza figlia, un’associazione sola | le regole delle figlie e la copertura sovrapposta |
| solo le figlie | le regole delle figlie | le persone senza figlia; nome e cognome scritti due volte |
| padre e figlie | tutte le informazioni | la semplicità delle interrogazioni, e il controllo della copertura |
Nessuno dei tre modi va bene in ogni caso. Chi progetta sceglie guardando che cosa il dominio non può permettersi di perdere: con Hagrid da registrare, il modo “solo le figlie” è escluso; con tante interrogazioni su studenti e professori insieme, “padre e figlie” costa un incrocio a ogni domanda.
Un database registra soltanto gli studenti e i professori dell’anno scolastico in corso, sotto l’entità persona. Che copertura ha la generalizzazione?
Nel diagramma della lezione l’entità studente ha un solo attributo, anno. Uno studente ha un nome?
Il database deve registrare anche Hagrid, che non è né studente né professore. Quale dei tre modi di trasformare la generalizzazione in tabelle non può farlo?