|
IMPLEMENTAZIONE
L'utilizzo della base di dati deve avvenire, come detto, principalmente per mezzo di Internet, per cui l'applicazione
verrà realizzata con script ASP (Active Server Pages) che utilizzano l'interfaccia ADO
(ActiveX Data Object) per l'accesso alla base di dati; il linguaggio di scripting che utilizzeremo sarà
JavaScript.
Non è di interesse per gli scopi di questa documentazione entrare nel dettaglio di ogni aspetto dell'implementazione;
trattandosi di un lavoro volto a descrivere le modalità di progetto delle basi di dati, ci limiteremo in questa sede a
descrivere come le operazioni individuate in fase di Analisi dei Requisiti possano essere realizzate in termini di
interrogazioni sulla base di dati o di inserimento/aggiornamento/eliminazione dalla stessa.
Tutte le interazioni con la base di dati seguiranno un pattern simile al seguente:
// Apertura di una connessione al database
// Aggiornamento di dati nel database
e / oppure
// Recupero di dati dal database
// Utilizzo dei risultati dell'interrogazione
// Rilascio risorsee chiusura connessione
Ci occuperemo, in questa sede, solo di descrivere le istruzioni SQL necessarie ad espletare il compito; solo dove necessario
saranno forniti ulteriori dettagli implementativi (uso di transazioni, uso di cursori aggiornabili etc.).
INTERROGAZIONI
Le operazioni richieste dall'applicazione (vedi Analisi dei Requisiti) sono di aggiornamento, alcune, e altre di
interrogazione; queste ultime sono le più frequenti e ce ne occupiamo in questo paragrafo.
Per migliorare la leggibilità del codice, e in alcuni casi per rendere possibili interrogazioni altrimenti non realizzabili,
è opportuno definire delle viste sulla base di dati. Le viste, in Access, vengono dette query; una query può
essere definita utilizzando una interfaccia grafica oppure scrivendo direttamente l'istruzione SQL: adotteremo questo secondo
metodo.
Elenchiamo di seguito le query che abbiamo definito sulla nostra base di dati e vedremo, quindi, come le operazioni richieste
dall'applicazione possano essere facilmente espresse in base a tali query.
Query _Intervista00_Short
SELECT
I.IDredattore,I.IDartista,I.DataIntervista,I.TitoloIntervista
FROM
INTERVISTA AS I;
Query _Intervista01_Redattore
SELECT
I.*, R.CognomeRedattore,R.NomeRedattore
FROM
_Intervista00_Short AS I LEFT JOIN REDATTORE AS R ON I.IDredattore=R.UserID;
Questa query fornisce tutte le interviste, ciascuna con il relativo redattore. Si utilizza un join esterno per assicurare che
vengano restituite tutte le interviste, anche se di fatto è impossibile, visti i vincoli imposti, che a un record della
tabella INTERVISTA non sia correlato un record della tabella
REDATTORE.
Query _Intervista02_Redattore_Top3
SELECT
TOP 3 I.*,R.CognomeRedattore,R.NomeRedattore
FROM
_Intervista00_Short AS I LEFT JOIN REDATTORE AS R ON I.IDredattore=R.UserID
ORDER BY
I.DataIntervista DESC;
Questa query è analoga alla precedente, però restituisce solo le tre interviste più recenti.
Query _Recensione00_Short
SELECT
R.CodiceDisco,R.IDredattore,R.DataRecensione,R.TitoloRecensione
FROM
RECENSIONE AS R;
Query _Recensione01_Redattore
SELECT
X.*,R.CognomeRedattore,R.NomeRedattore
FROM
_Recensione00_Short AS X LEFT JOIN REDATTORE AS R ON X.IDredattore=R.UserID;
Questa query è analoga a quella che correla le interviste con i redattori.
Query _Recensione02_Redattore_Top3
SELECT
TOP 3 X.*,R.CognomeRedattore,R.NomeRedattore
FROM
_Recensione00_Short AS X LEFT JOIN REDATTORE AS R ON X.IDredattore=R.UserID
ORDER BY
X.DataRecensione DESC;
Questa query è come la precedente, ma restituisce solo le tre interviste più recenti.
Query _Artista00_Short
SELECT
IDartista,NomeArtista,NazioneArtista
FROM
ARTISTA;
Query _Disco00_Short
SELECT
D.Codice,D.TitoloDisco,D.CasaDiscografica,D.AnnoDisco,G.IDgenere,G.NomeGenere
FROM
DISCO AS D LEFT JOIN GENERE AS G ON D.IDgenere=G.IDgenere;
Query _Disco01_Recensione
SELECT
D.*,R.IDredattore,R.CognomeRedattore,R.NomeRedattore,R.TitoloRecensione,R.DataRecensione
FROM
_Disco00_Short AS D LEFT JOIN _Recensione01_Redattore AS R ON D.Codice=R.CodiceDisco;
Questa query restituisce i dischi ciascuno con i dati relativi alla recensione del disco (compresi i dati del redattore); si usa il
join esterno per assicurarsi che vengano recuperati tutti i dischi, anche quelli che non hanno recensione.
Query _Disco02_Artisti
SELECT
D.*,A.IDartista,A.NomeArtista,A.NazioneArtista
FROM
_Disco00_Short AS D LEFT JOIN
(REALIZZAZIONE AS R LEFT JOIN _Artista00_Short AS A ON A.IDartista=R.IDartista)
ON D.Codice=R.CodiceDisco;
Questa query restituisce i dischi e, per ognuno di essi, i dati degli artisti che lo hanno realizzato; per ogni disco, quindi, si
avranno in generale più record nel risultato, uno per ogni artista che ha realizzato il disco.
Query _Disco03_Recensione_Artisti
SELECT
DR.*,DA.IDartista,DA.NomeArtista,DA.NazioneArtista
FROM
_Disco01_Recensione AS DR LEFT JOIN _Disco02_Artisti AS DA ON DR.Codice=DA.Codice;
Questa query non fa altro che combinare le due precedenti, restituendo così i dischi, ciascuno con la relativa recensione
(se esiste) e i dati degli artisti che lo hanno realizzato.
Questa query, o anche la precedente, può essere utilizzata per realizzare l'operazione OP06.
Query _Disco04_Short_Top5
SELECT
TOP 5 Codice,TitoloDisco,AnnoDisco,CasaDiscografica,
VotoMedio,NumeroVoti,Valutazione,D.IDgenere,NomeGenere
FROM
DISCO AS D LEFT JOIN GENERE AS G ON D.IDgenere=G.IDgenere
ORDER BY
Valutazione DESC,VotoMedio DESC,NumeroVoti DESC,AnnoDisco DESC,Codice;
Questa query restituisce i 5 dischi con il valore dell'attributo Valutazione più alto.
Query _Disco05_Recensione
SELECT
D.*,G.NomeGenere,R.IDredattore,R.CognomeRedattore,R.NomeRedattore,
R.TitoloRecensione,R.DataRecensione
FROM
(DISCO AS D LEFT JOIN GENERE AS G ON D.IDgenere=G.IDgenere)
LEFT JOIN _Recensione01_Redattore AS R ON D.Codice=R.CodiceDisco;
Questa query è analoga a _Disco02_Recensione, con l'unica differenza che, per ogni disco, fornisce
anche l'indicazione del genere del disco.
Query _Disco06_Recensione_Artisti
SELECT
DR.*,DA.IDartista,DA.NomeArtista,DA.NazioneArtista
FROM
_Disco05_Recensione AS DR LEFT JOIN _Disco02_Artisti AS DA ON DR.Codice=DA.Codice;
Questa query è analoga a _Disco03_Recensione_Artisti, ma fornisce anche il genere di ogni disco.
Query __Recensione__Recenti
SELECT
R.*,D.TitoloDisco,D.AnnoDisco,D.IDgenere,D.NomeGenere,D.CasaDiscografica,
D.IDartista, D.NomeArtista, D.NazioneArtista
FROM
_Recensione02_Redattore_Top3 AS R LEFT JOIN _Disco02_Artisti AS D ON R.CodiceDisco=D.Codice
ORDER BY
R.DataRecensione DESC,D.AnnoDisco DESC,R.CodiceDisco,D.NomeArtista;
Questa query restituisce le recensioni più recenti, con i dati del disco recensito; per ogni disco vengono forniti anche i
dati relativi agli artisti che lo hanno realizzato. Riguardo quest'ultimo aspetto, osserviamo che la query
_Recensione02_Redattore_Top3 riveste una particolare importanza in quanto permette si selezionare
"preventivamente" le recensioni più recenti, cosa che non si sarebbe potuta fare "direttamente" in
questa interrogazione utilizzando la specifica TOP 3 in quanto per ogni disco (e quindi per ogni
recensione) vi sono in generale più record, uno per ogni artista che ha realizzato il disco.
Questa query realizza l'operazione OP01.
Query __Intervista__Recenti
SELECT
I.*,A.NomeArtista,A.NazioneArtista
FROM
_Intervista02_Redattore_Top3 AS I LEFT JOIN _Artista00_Short AS A ON I.IDartista=A.IDartista
ORDER BY
I.DataIntervista DESC,A.NomeArtista,I.CognomeRedattore;
Questa query restituisce le tre interviste più recenti, con i dati dell'artista intervistato.
Questa query realizza l'operazione OP02.
Query __Disco__Preferiti
SELECT
D.*,A.IDartista,A.NomeArtista,A.NazioneArtista
FROM
_Disco04_Short_Top5 AS D LEFT JOIN
(REALIZZAZIONE AS R LEFT JOIN _Artista00_Short AS A ON A.IDartista=R.IDartista)
ON D.Codice=R.CodiceDisco
ORDER BY
D.Valutazione DESC,D.VotoMedio DESC,D.NumeroVoti DESC,D.AnnoDisco DESC,D.Codice,A.NomeArtista;
Questa query restituisce i dati dei 5 dischi che presentano il valore più alto di Valutazione,
unitamente ai dati degli artisti che lo hanno realizzato. Ancora, la query _Disco04_Short_Top5 riveste
grande importanza perché ci permette di selezionare in anticipo i 5 dischi "preferiti".
Questa query realizza l'operazione OP03.
Query __Disco__Genere
SELECT
D.*
FROM
_Disco02_Artisti AS D
ORDER BY
D.NomeGenere,D.TitoloDisco,D.Codice,D.NomeArtista;
Questa query è banale: restituisce i dischi e i relativi artisti. La utilizziamo solo per ragioni di leggibilità.
Questa query può essere utilizzata per realizzare l'operazione OP07.
Query __Disco__All
SELECT
DR.*,DA.IDartista,DA.NomeArtista,DA.NazioneArtista,B.NumeroBrano,B.TitoloBrano
FROM
(_Disco05_Recensione AS DR LEFT JOIN _Disco02_Artisti AS DA ON DR.Codice=DA.Codice)
LEFT JOIN BRANO AS B ON DR.Codice=B.CodiceDisco
ORDER BY
DR.TitoloDisco,DR.Codice,DA.NomeArtista,B.NumeroBrano;
Questa query restituisce tutti i dati relativi a ciascun disco, compresi i dati della recensione (se esiste, altrimenti i campi
corrispondenti assumeranno valore NULL), i dati degli artisti che hanno realizzato il disco, l'elenco
dei brani del disco. L'utilizzo dei join esterni è fondamentale per assicurare che vengano riportati tutti i dischi,
indipendentemente dal fatto che abbiano o meno la recensione o dei brani.
Questa query può essere utilizzata per realizzare l'operazione OP09.
Query __Artista__Genere
SELECT
A.*,G.IDgenere,G.NomeGenere
FROM
_Artista00_Short AS A INNER JOIN
(CARATTERIZZAZIONE AS C LEFT JOIN GENERE AS G ON C.IDgenere=G.IDgenere)
ON A.IDartista=C.IDartista;
Questa query restituisce gli artisti e, per ciascuno di essi, restituisce i generi che lo caratterizzano; gli attributi relativi
al genere saranno ovviamente nulli per gli artisti che non hanno realizzato alcun disco e quindi non sono caratterizzati da alcun
genere. La query è banale e la utilizziamo per mere ragioni di leggibilità.
Questa query può essere utilizzata per realizzare l'operazione OP05.
Query __Artista__All
SELECT
A.*,S.Url,I.DataIntervista,I.TitoloIntervista,I.IDredattore AS IDredInt,
I.CognomeRedattore AS CognRedInt,I.NomeRedattore AS NomRedInt,
D.Codice,D.TitoloDisco,D.CasaDiscografica,D.AnnoDisco,D.IDgenere,D.NomeGenere,
D.DataRecensione,D.TitoloRecensione,D.IDredattore AS IDredRec,
D.CognomeRedattore AS CognRedRec,D.NomeRedattore AS NomRedRec,
D.IDartista AS artID,D.NomeArtista AS artNome,D.NazioneArtista AS artNazione
FROM
((ARTISTA AS A LEFT JOIN _Intervista01_Redattore AS I ON A.IDartista=I.IDartista)
LEFT JOIN
(REALIZZAZIONE AS R LEFT JOIN _Disco03_Recensione_Artisti AS D ON R.CodiceDisco=D.Codice)
ON A.IDartista=R.IDartista) LEFT JOIN SITO AS S ON A.IDartista=S.IDartista
ORDER BY
A.NomeArtista,S.Url,D.TitoloDisco,D.Codice,D.NomeArtista,I.DataIntervista,I.IDredattore;
Questa query è, forse, la più complessa; essa restituisce tutti i dati relativi a ciascun artista, compresi i siti,
le interviste rilasciate dall'artista, i dischi realizzati e, per ciascuno di questi, l'elenco degli artisti che lo hanno realizzato.
Osserivamo l'utilizzo dei join esterni, necessari per assicurare che vengano forniti anche i dati relativi agli artisti che non hanno
siti, o che non hanno rilasciato interviste, o che non hanno realizzato dischi.
Questa query può essere utilizzata per realizzare l'operazione OP08.
Osserviamo che l'operazione OP04 può essere realizzata interrogando direttamente la tabella
ARTISTA, senza alcuna necessità di utilizzare una query.
Osserviamo anche che le operazioni OP08 e OP09 si sarebbe potute realizzare diversamente. La
soluzione adottata, in entrambi i casi, permette di realizzare l'intera operazione mediante una sola interrogazione e quindi
accedendo una sola volta alla base di dati; per contro, il risultato è costituito da una grosssa quantità di
informazioni con moltissima ridondanza: ad esempio, nel caso di un disco realizzato da 8 artisti e che ha 10 brani, il risultato
sarà una tabella di 80 record e, in ognuno di essi, le informazioni relative al disco (titolo, anno, casa discografica,
recensione etc.) si ripetono tal quali; ciò aumenta i tempi di trasferimento dei dati dalla base di dati all'applicazione.
Inoltre, i dati stessi non sono opportunamente strutturati e quindi è necessario un certo sforzo di programmazione per
organizzarli opportunamente, il che richiede tempo di elaborazione. Per contro, le stesse operazioni si possono realizzare mediante
più interrogazioni distinte (ad esempio, per un disco si possono prima prelevare i dati propri del disco, poi quelli degli
artisti che lo realizzano, poi quelli relativi ai brani inclusi); questa seconda soluzione è di certo più leggibile,
non richiede sforzo di programmazione per organizzare i dati e riduce la quantità di informazioni che devono essere trasferite
dal database all'applicazione; lo svantaggio consiste nel fatto che occorre accedere in più riprese alla base di dati e ogni
accesso ha bisogno del suo tempo affinché venga stabilita la connessione al database. Un esame attento dei tempi di
esecuzione, in presenza di diverse situazioni di carico sulla base di dati (accessi simultanei da parte di più utenti) e
di diverse istanze della base di dati, esula dagli scopi di questa trattazione ma, nella realtà, andrebbe effetutata con cura.
AGGIORNAMENTI
Le operazioni di aggiornamento saranno organizzate in transazioni, secondo il seguente pattern (dove
conn è un oggetto ADO Connection):
conn.Open(); //Apertura connesisone al database
try {
conn.BeginTrans(); //Inizio transazione
// ... operazioni di aggiornamento
conn.CommitTrans(); //Transazione conclusa con successo
}
catch(err) {
//Si è verificato un errore nel blocco try
conn.RollBackTrans(); //Transazione annullata
}
finally {
conn.Close();
};
Operando in questo modo, qualunque errore si verifichi nel blocco try, eventualmente anche un tentativo di aggiornamento alla base di
dati che ne violi le regole di integrità, viene "catturato" facendo sì che la transazione venga annullata, il
che comporta il ripristino delle condizioni precedenti all'inizio della transazione, assicurando così la consistenza della base
di dati. Il meccanismo delle transazioni deve essere usato in quanto, per molte delle operazioni richieste, è necessario
effettuare modifiche dei dati in tabelle diverse e tra loro correlate ed è quindi necessario impedire che solo una parte degli
aggiornamenti necessari venga eseguita, la qual cosa porterebbe inevitabilmente ad una inconsistenza nei dati. In particolare, le
transazioni sono utilizzate per assicurare il rispetto dei vincoli di integrità interrelazionali discussi in
Progettazione Fisica che non abbiamo potuto esprimere nella definizione della base dei dati, a causa delle limitazioni di
Access (che, in particolare, non permette l'utilizzo di comandi SQL come check o
create assertion).
Non ci soffermeremo sulle singole operazioni di aggiornamento ma piuttosto descriveremo in dettaglio la sequenza dei passi da seguire
per portare a termine l'operazione; descrizioni più accurate saranno fornite dove necessario.
Prima di continuare, facciamo una osservazione sui cursori utilizzabili in ADO; per quanto ci interessa, considereremo essenzialmente
due tipi di cursori: statico, che consente la sola lettura dei dati, e dinamico, che consente anche l'aggiornamento.
L'utilizzo di quest'ultimo è necessario in alcuni casi. Consideriamo il semplice esempio dell'inserimento di un nuovo disco,
immaginando per semplicità che esso sia realizzato da un solo artista già presente nella base di dati e caratterizzato
dal valore x per l'attributo IDartista. Per inserire il nuovo disco, dovremo inserire i
valori forniti nella tabella DISCO e poi dovremo anche inserire un record in
REALIZZAZIONE per indicare che il disco è realizzato dall'artista x; il
problema sorge perché il valore da assegnare al campo IDartista nel nuovo record di
REALIZZAZIONE è noto, mentre non lo è il valore da assegnare al campo
CodiceDisco, in quanto il campo Codice in
DISCO è definito come Contatore, e quindi è il DBMS che assegna
automaticamente il valore ad esso. Per poter ricavare con sicurezza il valore che è stato assegnato a
Codice per il nuovo record inserito in DISCO, al fine di poterlo
utilizzare per inserire correttamente il nuovo record in REALIZZAZIONE, dovremo usare un cursore
dinamico. Un tale cursore ammette un metodo AddNew che consente di inserire un nuovo record nella
struttura sulla quale il cursore è definito (nel nostro caso, la tabella DISCO); dopo
l'esecuzione del metodo AddNew, il cursore si posiziona proprio sul record appena inserito per
cui basta prelevare il valore corrispondente del campo di interesse (Codice, nel nostro esempio). Ecco
la sintassi utilizzata a tale scopo (dove conn è un oggetto ADO Connection):
var ElencoNomiCampi = new Array(...);
var ElencoValori = new Array(...);
var r = Server.CreateObject("ADODB.Recordset");
r.CursorType = 0;
r.LockType = 3; //Cursore dinamico utilizzabile per aggiornamenti
r.Open("SELECT * FROM DISCO",conn);
r.AddNew(ElencoNomiCampi,ElencoValori);
// Il cursore è ora posizionato sul record appena inserito
var CodiceNuovoDisco = String(r.Fields.Item("Codice").value);
r.Close();
// Il valore di CodiceNuovoDisco può ora essere usato
// per operare correttamente sulle altre tabelle da aggiornare
Nel seguito, ipotizzeremo di aver definito una funzione:
dynInsert(conn,NomeTabella,ElencoNomiCampi,ElencoValori,NomeCampoRitorno)
che realizzi le operazioni appena descritte, restituendo il valore che, per il nuovo record, è stato assegnato al campo il
cui nome è stato fornito in NomeCampoRitorno; relativamente all'esempio di sopra, si sarebbe
potuta chiamare la funzione come:
var CodiceNuovoDisco=dynInsert(conn,"DISCO",ElencoNomiCampi,ElencoValori,"Codice")
Vediamo come ogni operazione possa essere implementata.
OPERAZIONE OP10
Modifica voto medio, numero voti e valutazione disco
L'utente immette un voto (numero fra 0 e 10) per uno specifico disco; i valori dei campi del record vengono modificati secondo la
formula vista in precedenza (vedi Progettazione ...); sia NuovoVoto la variabile numerica
contenente il valore scelto dall'utente e CodiceDiscoCorrente il codice del disco votato.
UPDATE DISCO SET
NumeroVoti=NumeroVoti+1,
VotoMedio=(NumeroVoti*VotoMedio+NuovoVoto)/(NumeroVoti+1),
Valutazione=(NumeroVoti*VotoMedio+NuovoVoto)
WHERE Codice=CodiceDiscoCorrente
Occorre, però, fare i conti con la precisione macchina; infatti è possibile che, a causa delle inevitabili
approssimazioni nei calcoli matematici, alcuni valori violino il vincolo di integrità
Valutazione=VotoMedio*NumeroVoti, ancorché i dati siano in effetti validi; per ovviare al
problema "alleggeriamo" il vincolo, imponendo non l'uguaglianza stretta ma l'uguaglianza approssimata, ammettendo errori
dell'1%; ciò può essere fatto formulando il vincolo come segue:
(Valutazione*0,99 < VotoMedio*NumeroVoti) AND (VotoMedio*NumeroVoti < Valutazione*1,01)
OPERAZIONE OP12
Inserimento recensione
DATI FORNITI DALL'UTENTE
-
Titolo Recensione
-
Testo Recensione
-
Voto Recensione
-
Disco Recensito (Codice)
DATI RICAVATI DALL'APPLICAZIONE
-
Data Recensione
-
Redattore (UserID)
PASSI TRANSAZIONE
-
Inserimento nuovo record in tabella RECENSIONE
IMPLEMENTAZIONE
var values=...;
/*
Costruzione dell'array di valori forniti dall'utente e ricavati dall'applicazione;
la data/ora della recensione è posta pari alla data/ora corrente;
Il valore per IDredattore si può ricavare in quanto il redattore ha effettuato il login
*/
var SQL=
"INSERT INTO RECENSIONE "+
"(TitoloRecensione,TestoRecensione,DataRecensione,"+
"VotoRecensione,CodiceDisco,IDredattore) "+
"VALUES ("+values+")";
conn.Execute(SQL);
OPERAZIONE OP13
Inserimento intervista
DATI FORNITI DALL'UTENTE
-
Titolo Intervista
-
Testo Intervista
-
Artista Intervistato (IDartista)
DATI RICAVATI DALL'APPLICAZIONE
-
Data Intervista
-
Redattore (UserID)
PASSI TRANSAZIONE
-
Inserimento nuovo record in tabella INTERVISTA
IMPLEMENTAZIONE
var values=...;
/*
Costruzione dell'array di valori forniti dall'utente e ricavati dall'applicazione;
la data/ora della intervista è posta pari alla data/ora corrente;
Il valore per IDredattore si può ricavare in quanto il redattore ha effettuato il login
*/
var SQL=
"INSERT INTO INTEVISTA "+
"(TitoloIntervitsa,TestoIntervista,DataIntervista,"+
"IDartista,IDredattore) "+
"VALUES ("+values+")";
conn.Execute(SQL);
OPERAZIONE OP14
Modifica recensione
DATI FORNITI DALL'UTENTE
- Titolo Recensione
- Testo Recensione
- Voto Recensione
DATI RICAVATI DALL'APPLICAZIONE
PASSI TRANSAZIONE
-
Aggiornamento dei campi (TitoloRecensione,TestoRecensione,VotoRecensione) del record della tabella
RECENSIONE avente valore del campo CodiceDisco pari al valore dato
IMPLEMENTAZIONE
var SQL=
"UPDATE RECENSIONE SET "+
"TitoloRecensione='"+titoloRec+"',"+
"TestoRecensione='"+testoRec+"',"
"VotoRecensione="+votoRec+" "
"WHERE CodiceDisco="+codiceDisco;
conn.Execute(SQL);
OPERAZIONE OP15
Modifica intervista
DATI FORNITI DALL'UTENTE
-
Titolo Intervista
-
Testo Intervista
DATI RICAVATI DALL'APPLICAZIONE
-
Artista Intervistato (IDartista)
-
Redattore (UserID)
-
Data Intervista (DataIntervista)
PASSI TRANSAZIONE
-
Aggiornamento dei campi (TitoloIntervista,TestoIntervista) del record della tabella
INTERVISTA avente valori dei campi
(UserID,IDartista,DataIntervista) pari ai valori dati
IMPLEMENTAZIONE
var SQL=
"UPDATE INTERVISTA SET "+
"TitoloIntervista='"+titoloInt+"',"+
"TestoIntervista='"+testoInt+"',"
"WHERE IDartista="+IDartista+
" AND IDredattore="+userid+
" AND DataIntervista=#"+dataInt+"#";
conn.Execute(SQL);
OPERAZIONE OP16
Inserimento artista
DATI FORNITI DALL'UTENTE
-
Nome Artista
-
Descrizione
-
Nazione
-
Percorso File Foto
DATI RICAVATI DALL'APPLICAZIONE
PASSI TRANSAZIONE
-
Inserimento nuovo record in tabella ARTISTA
IMPLEMENTAZIONE
var values=...;
/*
Costruzione dell'array di valori forniti dall'utente
*/
var SQL=
"INSERTI INTO ARTISTA"+
"(NomeArtista,DescrizioneArtista,NazioneArtista,FotoArtista) "+
"VALUES ("+values+")";
conn.Execute(SQL);
OPERAZIONE OP17
Inserimento disco
DATI FORNITI DALL'UTENTE
-
Titolo Disco
-
Anno Disco
-
Casa Discografica
-
Foto
-
Genere (IDgenere) oppure Nuovo Nome Genere
-
Elenco brani (NumeroBrano,TitoloBrano)
-
Elenco artisti (elenco IDartista)
DATI RICAVATI DALL'APPLICAZIONE
PASSI TRANSAZIONE
-
Se Nuovo Nome Genere:
-
Apri cursore dinamico su GENERE
-
Inserisci in GENERE nuovo record
-
Preleva il valore assegnato, per il nuovo record, a IDgenere
-
Chiudi cursore su GENERE
-
Apri cursore dinamico su DISCO
-
Inserimento record in tabella DISCO, campi
(TitoloDisco,AnnoDisco,CasaDiscografica,FotoDisco,IDgenere)
NB: IDgenere è il valore assegnato direttamente dall'utente oppure, se l'utente ha chiesto di inserire
un nuovo genere, è il valore ricavato al passo 1.c
-
Preleva il valore del campo Codice del disco appena immesso
-
Chiudi cursore su DISCO
-
Inserisci nuovi record in BRANO con i valori di
(NumeroBrano,TitoloBrano) forniti dall'utente e il valore
CodiceDisco pari al valore Codice ottenuto al punto 4
-
Per ogni IDartista specificato:
-
inserimento della coppia (CodiceDisco,IDartista) nella tabella
REALIZZAZIONE, dove CodiceDisco è pari al valore di
Codice ottenuto al punto 4
-
se non esiste, in CARATTERIZZAZIONE, un record
(IDartista,IDgenere) allora inserisci nuovo record
(IDartista,IDgenere) nella tabella CARATTERIZZAZIONE
IMPLEMENTAZIONE
/* Definizione delle variabili contenenti i valori da inserire */
var titoloDisco=..., annoDisco=..., casaDisc=..., fotoDisco=...;
/* Booleana, vera se occorre inserire un nuovo genere */
var insertNuovoGenere=...;
/* Hanno senso l'una o l'altra, a seconda che si debba inserire o meno un nuovo genere: */
var idGenereDato=..., nomeNuovoGenere=...;
/* Array contenenti l'elenco ordinato dei titoli dei brani e i valori del campo IDartista per gli artisti che hanno realizzato
il disco */
var brani=..., artisti=...;
if (insertNuovoGenere)
var idGenere=dynInsert(conn,"GENERE",("NomeGenere"),(nomeNuovoGenere),"IDgenere")
else
var idGenere=idGenereDato;
var nomiCampi=new Array("TitoloDisco","AnnoDisco",CasaDiscografica",FotoDisco","IDgenere");
var elencoValori=new Array(titoloDisco,annoDisco,casaDisc,fotoDisco,idGenere);
var codiceDisco=dynInsert(conn,"DISCO",nomiCampi,elencoValori,"Codice");
var SQL="", i=0;
for (i=0; i<brani.length; i++) {
SQL="INSERT INTO BRANO (NumeroBrano,TitoloBrano,CodiceDisco) "+
"VALUES ("+String(i+1)+",'"+brani[i].replace(/'/g,"''")+"',"+
codiceDisco+")";
conn.Execute(SQL);
};
for (i=0; i<artisti.length; i++) {
SQL="INSERT INTO REALIZZAZIONE (CodiceDisco,IDartista) "+
"VALUES ("+codiceDisco+","+artisti[i]+")";
conn.Execute(SQL);
var r=Server.CreateObject("ADODB.Recordset");
SQL="SELECT * "+
"FROM CARATTERIZZAZIONE "+
"WHERE IDartista="+artisti[i]+" AND IDgenere="+idGenere;
r=conn.Execute(SQL);
var caratterizzato=!(r.EOF && r.BOF);
delete r;
if (!caratterizzato) {
SQL="INSERT INTO CARATTERIZZAZIONE (IDartista,IDgenere) "+
"VALUES ("+artisti[i]+","+idGenere+")";
conn.Execute(SQL);
}; //end if
}; //end for
NOTA: Piuttosto che effettuare una interrogazione per verificare se un artista risulta già caratterizzato in
base a un genere, si può piuttosto inserire il record (IDartista,IDgenere) in
CARATTERIZZAZIONE utilizzando un blocco try...catch: se esiste
già un record uguale (cioè, l'artista è già caratterizzato in base a quel genere) il tentativo di
inserimento verrà rifiutato e provocherà un errore il quale, però, è "catturato" e non provoca
l'annullamento della transazione; se, invece, non esiste un tale record, il record verrà correttamente inserito come richiesto.
Pertanto, il ciclo for (i=0; i<artisti.length; i++) può essere riscritto come segue:
for (i=0; i<artisti.length; i++) {
SQL="INSERT INTO REALIZZAZIONE (CodiceDisco,IDartista) "+
"VALUES ("+codiceDisco+","+artisti[i]+")";
conn.Execute(SQL);
try {
SQL="INSERT INTO CARATTERIZZAZIONE (IDartista,IDgenere) "+
"VALUES ("+artisti[i]+","+idGenere+")";
conn.Execute(SQL); }
catch(insertRejected) {
/*Nessuna azione*/ };
}; //end for
OPERAZIONE OP18
Modifica artista
DATI FORNITI DALL'UTENTE
-
Nome Artista
-
Descrizione Artista
-
Nazione Artista
-
Percorso File Foto
-
Elenco URL da eliminare
-
Elenco URL da aggiungere
DATI RICAVATI DALL'APPLICAZIONE
PASSI TRANSAZIONE
-
Aggiornamento record tabella ARTISTA avente valore del campo
IDartista pari al valore dato
-
Eliminazione da SITO dei record aventi campi Url e
IDartista pari ai valori dati
-
Inserimento in SITO delle coppie di valori (IDartista,Url)
fornite
IMPLEMENTAZIONE
var SQL=
"UPDATE ARTISTA SET "+
"NomeArtista='"+nomeArtista+"',"+
"DescrizioneArtista='"+descrArtista+"',"
"NazioneArtista="+nazioneArtista+" "
"FotoArtista="+fotoArtista+" "
"WHERE IDartista="+idArtista;
conn.Execute(SQL);
for (var i=0; i<urlDaEliminare.length; i++) {
SQL=
"DELETE FROM SITO "+
"WHERE IDartista="+idARtista+"AND "+
"Url='"+urlDaEliminare[i]+"'";
conn.Execute(SQL);
};
for (i=0; i<urlDaAggiungere.length; i++) {
SQL=
"INSERT INTO SITO (IDartista,Url) "+
"VALUES ("+idArtista+",'"+
urlDaAggiungere[i]+"')";
conn.Execute(SQL);
};
OPERAZIONE OP19
Modifica disco
DATI FORNITI DALL'UTENTE
-
Titolo Disco
-
Anno Disco
-
Casa Discografica
-
Percorso File Foto
-
Genere (IDgenere)
-
Eventualmente, Elenco Brani (NumeroBrano,TitoloBrano)
-
Eventualmente, artisti che devono essere tolti dalla realizzazione (IDartista)
-
Eventualmente, artisti che devono essere aggiunti alla realizzazione (IDartista)
DATI RICAVATI DALL'APPLICAZIONE
PASSI TRANSAZIONE
-
Aggiornamento campo della tabella DISCO avente valore del campo
Codice pari al valore dato; consideriamo i valori
IDgenereVecchio e IDgenereNuovo; tali valori sono uguali se non si
è modificato il genere del disco (NB: tali valori sono entrambi dati)
-
Se vi è un nuovo elenco brani, cancella da BRANO tutti i record aventi
CodiceDisco pari al valore dato, quindi inserisci in BRANO i
nuovi record con i valori (NumeroBrano,TitoloBrano) forniti dall'utente e il valore
CodiceDisco dato
-
Per ogni artista (se presente) da togliere dalla realizzazione del disco:
-
Eliminazione da REALIZZAZIONE del record avente CodiceDisco
e IDartista pari ai valori dati
-
Verifica, attraverso le tabelle REALIZZAZIONE-DISCO, se esistono dischi del genere
IDgenereVecchio realizzati dall'artista; se non esistono, elimina il record
(IDartista,IDgenereVecchio) da CARATTERIZZAZIONE
-
Per ogni artista (se presente) da aggiungere alla realizzazione del disco:
-
Inserimento in REALIZZAZIONE della coppia
(CodiceDisco,IDartista) data
-
Se non esiste già un record (IDartista,IDgenereNuovo) in
CARATTERIZZAZIONE, aggiungilo
IMPLEMENTAZIONE
/* Definizione delle variabili */
var titoloDisco=..., annoDisco=..., casaDisc=..., fotoDisco=...;
var codice=...,idGenereVecchio=...,idGenereNuovo=...;
/* Array contenenti il nuovo elenco ordinato dei titoli dei brani del disco, l'elenco degli artisti da aggiungere
alla realizzazione del disco e l'elenco degli artisti da togliere dalla realizzazione del disco*/
var brani=...,artistiAdd=...,artistiDel=...;
var SQL="", i=0;
SQL="UPDATE DISCO SET "+
"TitoloDisco='"+titoloDisco+"',"+
"AnnoDisco="+annoDisco+","+
"CasaDiscografica='"+casaDisc+"',"+
"FotoDisco='"+fotoDisco+"',"+
"IDgenere="idGenereNuovo+
" WHERE Codice="+codice;
conn.Execute(SQL);
if (brani.length>0) {
SQL="DELETE FROM BRANI WHERE CodiceDisco="+codice;
conn.Execute(SQL);
for (i=0; i<brani.length; i++) {
SQL="INSERT INTO BRANO (NumeroBrano,TitoloBrano,CodiceDisco) "+
"VALUES ("+String(i+1)+",'"+brani[i].replace(/'/g,"''")+"',"+ codice+")";
conn.Execute(SQL);
};
};
for (i=0; i<artistiDel.length; i++) {
SQL="DELETE FORM REALIZZAZIONE WHERE "+
"IDartista="+artistiDel[i]+" AND "+
"CodiceDisco="+codice;
conn.Execute(SQL);
SQL="DELETE FROM CARATTERIZZAZIONE WHERE "+
"IDartista="+artistiDel[i]+
" AND IDgenere="+idGenereVecchio+
" AND NOT EXISTS ("+
"SELECT * FROM "+
"(DISCO AS D LEFT JOIN GENERE AS G ON D.IDgenere=G.IDgenere) "+
"RIGHT JOIN REALIZZAZIONE AS R ON R.CodiceDisco=D.Codice "+
"WHERE "+
"(R.IDartista="+artistiDel[i]+" AND"+
" G.IDgenere="+idGenereVecchio+")"+
")";
conn.Execute(SQL);
};
for (i=0; i<artistiAdd.length; i++) {
SQL="INSERT INTO REALIZZAZIONE (CodiceDisco,IDartista) "+
"VALUES ("+codiceDisco+","+artistiAdd[i]+")";
conn.Execute(SQL);
var r=Server.CreateObject("ADODB.Recordset");
SQL="SELECT * "+
"FROM CARATTERIZZAZIONE "+
"WHERE IDartista="+artistiAdd[i]+
" AND IDgenere="+idGenereNuovo;
r=conn.Execute(SQL);
var caratterizzato=!(r.EOF && r.BOF);
delete r;
if (!caratterizzato) {
SQL="INSERT INTO CARATTERIZZAZIONE (IDartista,IDgenere) "+
"VALUES ("+artistiAdd[i]+","+idGenereNuovo+")";
conn.Execute(SQL);
}; //end if
}; //end for
OPERAZIONE OP20
Eliminazione recensioni e interviste
DATI FORNITI DALL'UTENTE
DATI RICAVATI DALL'APPLICAZIONE
PASSI TRANSAZIONE
-
Elimina dalle tabelle RECENSIONE e INTERVISTA tutti i
record per i quali il valore del campo DataRecensione (ovvero
DataIntervista) rappresenta una data più vecchia di 6 mesi rispetto alla data odierna
IMPLEMENTAZIONE
Utilizziamo la funzione DateDiff, proprietaria di Access, che permette di calcolare intervalli
di tempo intercorrenti tra due date; l'implementazione è molto semplice.
var SQL=
"DELETE FROM RECENSIONE "+
"WHERE DateDiff('m',DataRecensione,Now())>6";
conn.Execute(SQL);
var SQL=
"DELETE FROM INTERVISTA "+
"WHERE DateDiff('m',DataIntervista,Now())>6";
conn.Execute(SQL);
|