Chiunque si sia trovato a relazionare un database con una pagina ASP ha dovuto, per forza di cose, gestire le proprietà CursorType e LockType. Il problema è che, nella maggior parte dei casi, il tutto è avvenuto quasi automaticamente senza realmente comprendere il significato di questi valori.
Ricordo che, i primi tempi che mi avvicinai ad ASP, da eterno curioso non riuscivo a spiegarmi cosa volessero dire quei numeri a fianco del comando di apertura del recordset. Soprattutto, non riuscivo a comprendere perché script apparentemente identici riportassero valori differenti.
Vediamo allora cosa sono questi due elementi. Prima di procedere prendiamo in esempio un normalissimo codice per l'apertura di un recordset.
strSQL = "SELECT * FROM nometabella"
objRs.Open objConn, strSQL, 1, 2
Analizzando la seconda riga, troviamo
- objRs.Open : il comando di apertura del recordset
- objConn : il parametro che definisce la connessione
- strSQL : il parametro che definisce la query SQL da eseguire
- 1 : il parametro che definisce il CursorType
- 2 : il parametro che definisce il LockType
CursorType
CursorType definisce il tipo di cursore di un recordset.
Per comprendere meglio la sua funzione immaginiamo per un attimo di accedere ad una tabella di un database Access attraverso la console di gestione. Non appena aperta la tabella noteremo un puntatore, gestibile attraverso la tastiera ed il mouse, posizionarsi sulla prima cella in alto a sinistra.
Questo cursore definisce il record (ovvero la riga) e la cella in cui ci troviamo e nella quale si rifletteranno eventuali comandi di aggiornamento o modifica.
L'utilità del cursore nel caso di una connessione al database tramite ASP è la stessa. Ci consente di navigare attraverso i record e di eseguire operazioni su di essi.
Tipi di Cursore
Esistono 4 tipi di cursori, ognuno con le proprie caratteristiche.
Forward Only(solo in avanti)
È il cursore predefinito quando non è specificato un valore alternativo.
Consente di muoversi solo in avanti attraverso i record. La costante ADO che lo
identifica è adOpenForwardOnly mentre il valore è 0.
Static(Statico)
Permette di spostarsi avanti ed indietro tra i record ma non riflette le modifiche
eseguite da altri utenti. La costante ADO che lo identifica è adOpenStatic
mentre il valore è 3.
Dynamic(Dinamico)
È il cursore più flessibile. Consente di muoversi avanti ed indietro
e riflette le modifiche eseguite da altri utenti. La costante ADO che lo identifica
è adOpenDynamic mentre il valore è 2.
Keyset(Set di tasti)
Permette lo spostamento avanti ed indietro, riflette le modifiche eseguite da
altri utenti ad eccetto dell'inserimento e della rimozione di record. La costante
ADO che lo identifica è adOpenKeyset mentre il valore è 1.
Impostazione del Cursore
Per impostare il tipo di cursore è possibile procedere in due modi: la proprietà .CursorType prima di aprire il recordset oppure la specifica del parametro in fase di esecuzione della query.
In entrambi i casi è possibile inserire il valore sia come costante ADO sia, scelta che raccomando, come valore numerico.
Nella logica di programmazione l'uso di una costante è più opportuna
poiché rende più intuitiva la comprensione del codice. Tuttavia,
ritengo inutile in questo caso imparare a memoria lunghi nomi di costanti per
la specifica di un parametro standard.
Il primo metodo, assumendo che objRs sia il nostro recordset, sarà
objRs.CursorType = 1 ' oppure la costante
mentre il secondo
objRs.Open objConn, strSQL, 1 ' oppure la costante
Conclusioni
Arrivati a questo punto molti potrebbero chiedersi lo scopo o l'utilità di comprendere l'utilizzo dei cursori.
Come anticipato, definire il cursore corretto è molto importante per due ragioni. In primo luogo consente di risparmiare risorse, in secondo luogo un cursore errato non permette di completare l'esecuzione di un comando.
Un cursore come Forward Only non permette, ad esempio, di eseguire la paginazione dei record.
Non solo, un cursore predefinito è anche la risposta al perché la proprietà .RecordCount restituisce -1 invece del reale numero di record. In questo caso è necessario impostare il cursore a 1.
LockType
LockType definisce il tipo di blocco per l'aggiornamento di un recordset.
Anche in questo caso possiamo comprendere meglio con un esempio. Riprendiamo il database Access di prima.
Fin tanto che sono io l'unico utilizzatore non ci saranno mai problemi di sovrascrittura dei dati. Ma cosa succederebbe se due persone tentassero di aggiornare contemporaneamente lo stesso dato? Quale dei due sarebbe il valore finale?
Per risolvere questo problema ADO mette a disposizione una serie di valori per consentire di attivare un blocco quando si eseguono modifiche su un recordset.
Tipi di Blocco
Esistono 4 tipologie differenti di blocco.
Read Only (Sola lettura)
E' il tipo di blocco predefinito e consente solo di leggere i record senza eseguire modifiche. Il principale vantaggio è quello di richiedere il minor numero necessario di risorse sul server.
La costante ADO che lo identifica è adLockReadOnly mentre il valore è 1.
Pessimistic (Pessimista)
E' il blocco più restrittivo. Nega l'accesso al record dal momento in cui viene richiesto di editarlo.
Il lato negativo è che questo blocco riduce il numero di record disponibile agli altri utenti, tuttavia è la soluzione più utilizzata in fase di aggiornamento.
La costante ADO che lo identifica è adLockPessimistic mentre il valore è 2.
Optimistic (Ottimista)
Il blocco nega l'accesso solo dal momento in cui la modifica è confermata. Fino a quel momento altri utenti potranno ancora visualizzare e modificare il record.
La costante ADO che lo identifica è adLockOptimistic mentre il valore è 3.
Batch Optimistic (Combinazione Ottimista)
Il blocco consente di modificare più record in una combinazione. I blocchi vengono attivati solo nel momento della conferma.
La costante ADO che lo identifica è adLockBatchOptimistic mentre il valore è 4.
Impostazione del Blocco
Per impostare il blocco è possibile procedere allo stesso modo come per il cursore.
La proprietà è .LockType mentre la posizione del parametro è la quarta, subito dopo allo spazio dedicato al cursore.
Nel caso si specifichi un blocco diverso da quello predefinito è necessario specificare un tipo di cursore, anche se quello predefinito.
Esempio
objRs.LockType = 2 ' oppure la costante
Esempio di blocco predefinito (indipendentemente dal cursore)
objRs.Open objConn, strSQL, 1
uguale a
objRs.Open objConn, strSQL
uguale a
objRs.Open objConn, strSQL, 1, 1
Esempio di blocco alternativo
objRs.Open objConn, strSQL, 1, 2
In questo ultimo caso è importante specificare anche il tipo di cursore, anche se si tratta del valore 0 predefinito.
Conclusioni
Anche in questo caso, ci si potrebbe chiedere a cosa serve il blocco.
Partendo dal presupposto che se qualcosa è stato creato è perché di norma serviva, parte di questa risposta è già stata chiarita nell'introduzione.
Il blocco è fondamentale per evitare la sovrascrittura di dati e la conseguente perdita di informazioni.
Definire il blocco corretto può voler significare risparmiare risorse sul server ed ottimizzare le prestazioni.
Per esempio, è inutile definire un blocco diverso da Read Only quando si sta semplicemente scorrendo un record senza eseguire modifiche.
Inoltre, è necessario ricordarsi che un blocco errato in fase di aggiornamento può causare errori tipo
Tipo di errore:
ADODB.Recordset (0x800A0CB3)
Il set di record corrente non supporta l'aggiornamento. Potrebbe trattarsi di una limitazione del provider o del tipo di blocco selezionato.
In questo caso ricordatevi di usare un blocco 2 o al massimo 3.