Gestire le query all'esterno dell'ASP


Home Page | Comments | Articles | Faq | Documents | Search | Archive | Tales from the Machine Room | Contribute
A cura di Davide Bianchi Mescolare i linguaggi (SQL ed ASP) non e' mai una buona cosa, utilizzando un paio di semplici accorgimenti e' possibile gestire le Query SQL all'esterno dei file ASP che le richiamano, rendendo il codice piu' pulito e facilmente mantenibile.

Manutenzione difficile A tutti sara' capitato: di dover mettere le mani su del codice ASP non fatto da noi e, nella fattispecie, di dover modificare una Query, per poi scoprire che quella maledetta query era richiamata da 52 pagine ASP diverse.

Risultato: una query=52 pagine modificate!

Dopo l'ennesima disavventura del tipo, ho finalmente deciso a mettere mano ad un sistema 'umano' per gestire questo tipo di problemi.

Tenere l'SQL fuori dall'ASP Cosa ci vuole per gestire le query in un modo 'decente'? In fondo una query altro non e' che un blocco di testo ASCII, a cui possono essere aggiunti dei parametri da valorizzare al momento di eseguirla, niente altro.

Ecco la mia pensata quindi: definire le query in un file (ASCII) quindi leggere il testo della query da ASP utilizzando l'FSO mediante una semplice funzione, utilizzare un'altra funzione per fare la sostituzione dei parametri et-voila', eseguire la query.

In questo modo si ottengono tre vantaggi:

  1. tutte le query sono memorizzate in un unico file che e' molto semplice da mantenere
  2. ad ogni query e' associato un ID 'descrittivo' che spiega lo scopo della query
  3. il programmatore/utente e' portato a riutilizzare le query piuttosto che a riscriverle.
Per implementare questo meccanismo si ha bisogno di due cose:
  1. Una funzione che 'legga' il file delle query ed 'identifichi' la query che stiamo cercando
  2. Una funzione che permetta la sostituzione dei parametri all'interno della query
Questi due semplici pezzi di codice possono essere messi in un file .ASP da includere nei propri progetti, come una semplice libreria di codice aggiuntivo.

Il formato delle Query Dato che non sono richieste informazioni 'apocalittiche' per questo tipo di attivita', ho deciso di gestire le query con un semplicissimo formato: il file delle query e' composto da linee, ogni linea rappresenta una query, ogni query e' composta di due parti separate da ';'

Codice identificativo ; testo della query

Non ci sono limiti alla lunghezza del codice e del testo della query, eventuali spazi prima e dopo il codice vengono 'ingoiati' dalla funzione che legge la query.

Eventuali parametri da sostituire nella query (clausola WHERE o ORDER BY) sono indicati con !n dove 'n' e' un numero progressivo.

Per quanto riguarda i parametri, qualunque sequenza di caratteri che non abbia significato in SQL potrebbe essere utilizzata ho scelto '!' semplicemente perche' sono sicuro che nessun dialetto SQL utilizza questa sequenza (mentre molti usano '#' come indicatore della data o $ come carattere jolly).

Un generico 'file di query' potrebbe essere il seguente:

TuttiGliArticoli;SELECT Titolo, Autore, DataPubblicazione FROM Documenti WHERE Documenti.IDTipo=0
TuttiGliAutoriPerAnno;SELECT Autore, Editore, Titolo FROM Documenti WHERE YEAR(DataPubblicazione)=!1
TuttiGliArticoliPerAutore;SELECT Titolo, Editore, Autore FROM Documenti WHERE Autore='!1'

Se vedessimo nel codice ASP una cosa del tipo:



Dim sql
sql = RecuperaQuery( "TuttiGliAutoriPerAnno", query.txt )
avremmo pochi dubbi su cosa sta' facendo quel pezzo di codice suppongo...

Il codice: trovare le query A questo punto ci manca il codice per reperire le query dal file, scomodiamo pertanto il FSO (FileSystemObject) per fare la parte (nota: il codice e' in JavaScript e non in VBScript):

/*
 * Cerca una query specificata per ID all'interno del
 * file indicato, ritorna la query cercata o NULL se
 * non trova nulla
 *
 */
function RecuperaQuery( qryID, fileName )
{
   var fso;           // FileSystemObject
   var file;          // Fiile usato per leggere le query
   var elem;          // elementi della query
   var query = null;  // query da ritornare
   var ro = / /g;     // elimina spazi
      
   // Creo un nuovo oggetto FileSystem
   fso=new ActiveXObject( "Scripting.FileSystemObject" );
   
   // accedo al file delle Query
   file = fso.OpenTextFile( fileName )

   // elimino gli spazi all'interno del codice
   qryID = qryID.replace( ro, "" );
   
   // ciclo e leggo tutte le query
   while( ! file.AtEndOfStream )
   {
      // leggo la singola query
      qry = file.ReadLine();
      
      // parserizzo suddividendo la query in Codice e
      // Testo ed elimino gli spazi
      elem = SeparaQuery( qry, null );
      elem[0] = elem[0].replace( ro, "" );
      
      // verifico di aver trovato la query che cercavo
      if( qryID == elem[0] )
      {
         // ritorno la query trovata
         query = elem[1];
         break;
      }
   }

   // chiudo il file delle query
   file.close();
   
   // ritorno la query trovata o Null
   return query;

}
Con questo semplice pezzo di codice siamo in grado di reperire le query leggendole dal file. L'unica parte di codice che potrebbe non essere molto chiara e' l'utilizzo della replace per eliminare gli spazi.

Qui' sto utilizzando una features del JScript che consente di usare una Regular Expression per effettuare un ricerca/sostituisci all'interno del testo.

Una trattazione completa delle Regular Expression e' al di la' degli scopi di questo articolo (sono stati scritti libri interi sull'argomento), bastera' sapere che lo scopo della funzione e' l'eliminazione di qualunque spazio all'interno della stringa.

N.B. non ho convertito il testo in maiuscolo/minuscolo, proprio per lasciare piu' possibilita' di scelta all'utente su come codificare le query. Eventualmente potrebbe essere utile fare la conversione e mettere tutto in minuscolo o maiuscolo.

Separare il codice dalla query La funzione RecuperaQuery, fa riferimento ad una fantomatica SeparaQuery, che dovrebbe dividere la linea letta ritornando i due elementi che la compongono: il Codice e la Query vera e propria, questa e' la funzione che ci serve:

/*
   SeparaQuery
   
   Separa una 'query' letta dal file in due elementi:
   un codice ed una stringa che vengono ritornati 
   in un array costruito per l'occasione.
   
   Parametri:
   query       e' la query letta dal file
   separatore  e' il carattere usato per dividere i due pezzi
   
*/
function SeparaQuery( query, separatore )
{
   var ro;
   
   // se il separatore non e' specificato assumo ";"
   if( sep == null )
   {
      ro = new RegExp( ";", "g" );
   }
   else
   {
      ro = new RegExp( sep, "g" );
   }

   return qry.split( ro );
   
}
L'uso di una RegularExpression per fare il lavoro ci mette al riparo da limitati errori di scrittura nel file delle query: se mettiamo due ; uno accanto all'altro (codicequery;;stringaquery), i due ';' verranno interpretati come uno solo dalla RegExp, ritornando quindi sempre la riga esatta!

Sostituire i parametri A questo punto manca la parte di codice che sostituisca nella stringa-query i vari parametri, usiamo di nuovo la potenza delle Regular Expression:

/*
   SostituisciParametro
   Sostituisce il parametro indicato nella query
   con il valore indicato

   query          query da elaborare
   paramNumber    numero di parametro da sostituire
   value          valore da inserire
   
   ATTENZIONE: se 'paramNumber' non viene trovato, 
               non viene fatta nessuna sostituzione ne'
               si segnala alcun errore.
               
*/
function SostituisciParametro( query, paramNumber, value )
{
   
   var pos;
   var newQuery = "";
   
   // preparo la RegularExpression per fare la sostituzione,
   // usando 'gi' sostituisco tutto (global) ed ignoro maiuscole
   // e minuscole (ignore case)
   var ro = new RegularExpression("!" + paramNumber, "gi")
   
   // effettuo la sostituzione
   newQuery = query.replace( ro, value );
      
   // ritorno la nuova query      
   return newQuery;
   
}
Un semplice esempio d'uso Il codice seguente legge una query dal nostro file, vi sostituisce alcuni parametri ed utilizza la query risultante.


Dim conn
Dim rs
Dim query

Set conn=Server.CreateObject("ADODB.Connection")
conn.Open "DSNNAME"

' recupero la query...
query = RecuperaQuery( "TuttiIRecordPerAnno",
                       Server.MapPath("query.lst") )
query = SostituisciParametr( query, 1, 1999 )

' faccio qualche cosa con il risultato
Set rs=conn.Execute( query )
'...

Non e' difficile intuire cosa faccia questo pezzo di codice, e l'assenza di codice SQL messo in mezzo rende la manutenzione assai piu' semplice.

Conclusione e miglioramenti Il codice presentato e' gia' un notevole miglioramento rispetto al mettere il codie SQL direttamente dentro all'ASP, un ulteriore miglioramento protrebbe essere la lettura di tutto il file query all'inizio (nel global.asa ad esempio), in modo da fare poi il 'pescaggio' delle query da un array in memoria, questo velocizzerebbe molto le cose, soprattutto quando le query diventano TANTE.

Un altra miglioria che ptrebbe essere fatta e' l'uso di un array di parametri nella SostituisciParametri, in modo da poter specificare tutti i parametri in una sola linea.


Comments

Max length of comments: 1000 chars.

nessun commento.

Add a comment (max 1000 chars)

Comment from:
Comment:


Author Davide Bianchi, works as Unix/Linux administrator for a "network security" company of Haarlem.
Contacts: mail: davide AT onlyforfun.net , ICQ: 268751033, Jabber: davideyeahsure AT gmail.com Skype: davideyahsure

Contribuire Volete contribuire? Leggete come!

Copyright This site is made by me with blood, sweat and gunpowder, if you want to republish or redistribute any part of it, please drop me (or the author of the article if is not me) a mail.

This site was composed with VIM, now is composed with VIM and the (in)famous CMS FdT.

This site isn't optimized for vision with any specific browser, nor it requires special fonts or resolution.
You're free to see it as you wish.
Web Interoperability Pleadge is this a valid html document?

Last Update: 04/12/2008