Newsgroup: it.comp.lang.visual-basic
Titolo: [OT lungo] Alcune dritte VB trovate allo SMAU

Ciao ragazzi,
quest'anno sono andato allo SMAU lunedì, durante il pomeriggio,
appositamente per seguire le sessioni ms su .net e compagnia
bella......oltre alla spiegazione e alla presentazione in sè, hanno dato
alcuni consigli che ho pensato fossero un po' utili a tutti. Per esempio:
*** ADO ***
Lo sapevate che se uso una sintassi del tipo
Msgbox Rs("Descrizione")
dove Rs è un oggetto di tipo ADODB.Recordset, il compilatore non fa altro
che "convertire" il nome del campo nel suo corrispondente indice all'interno
della tabella?
Per essere più chiari, se "Descrizione" è il terzo campo nella tabella,
diventa:
Msgbox Rs(2)
A quanto pare, questa conversione che il compilatore fa per noi porta via un
sacco di cicli macchina e sarebbe una bella cosa evitarla, indicando
direttamente l'indice.
Mi immagino, per esempio, tutte le volte che gestiamo il Form_Load per
riempire combobox e listbox con dei valori letti dalle tabelle: se gli
elementi da caricare sono centinaia o migliaia, si perde veramente un sacco
di tempo......
*** CONCATENZIONE DI STRINGHE NELL'SQL ***
Molto spesso, nel codice VB viene generata una stringa SQL da lanciare nel
db. Per esempio:
Sql="SELECT * FROM Utenti WHERE '" & Me.txtUsername & "' AND Password='" &
Me.txtPwd & "'"
ad esempio, per verificare che un utente esista nella tabella Utenti.
Giusto?
In realtà è giusto, ma è sconsigliabile, in quanto è stato dimostrato come
tramite un'istruzione fatta così possa essere usata anche per altri scopi.
Soprattutto nel caso in cui il db su cui stiamo lavorando accetti istruzioni
SQL una dietro l'altra separate da ;
il relatore ha consigliato invece di usare l'oggetto Command, ed utilizzare
query parametriche......
good coding!!!
--
Damiani Liborio Igor
ig...@igordamiani.it
 - 
dam...@italiainfiera.it
 - 
idam...@hotmail.com
http://www.igordamiani.it
ICQ : 11847262

 utilizzare query parametriche......
La giusta via è validare sempre il dato inserito dall'utente; imho
ovviamente! :)

 Msgbox Rs(2)
Certo... L'efficienza si riduce... però... vuoi mettere la leggibilità del
codice? Le possibilità di sbagliare... inoltre dovresti ogni volta
specificare tutti i campi nella query altrimenti impazzisci sull'ordine in
cui te li restituisce...
E poi... non credo che possa rallentare più di tanto se nel recordset ho 10
o 20 campi... :)
                Ciao
                                Allanon
--
- SPAMKILLER
 L'indirizzo delle risposte é 
itlangv...@michele.sytes.net
 LASCIATE il NOSPAM fa parte dell'indirizzo :-)
  Per superare le impostazioni di protezione antispam scrivete
  nel testo del messaggio la scritta "SPAMKILLER"
Scusate il disturbo, ma non posso più di pubblicità!

sai una cosa? avevo pensato anche io di non mettere [OT]  e di mettere
invece [!], però ho dato un'occhiata al manifesto. [!] si usa per la
risoluzione di bug importanti o comunicazioni importanti......
cmq, le tue considerazioni sono corrette, però in effetti può essere utile
nel caso in cui occorre riempire combobox o listbox con migliaia di record,
come l'elenco dei comuni, o dei CAP, o qualcosa di simile.......
per quanto riguarda la leggibilità, si potrebbe pensare di implementare
un'enumerazione, che associ ad ogni campo il corrispondente intero, che nel
caso:
Enum CampiTabellaClienti
    Codice=0
    Nome=1
    Indirizzo=2
    CAP=3
End Enum
non so se la sintassi è questa.......è pseudo-codice......però ho reso
l'idea?
che ne dici? che ne pensate?


 di tempo......
ok, ma lo puoi fare solo nell'ottimizzazione finale, quando sei sicuro
che la struttura del db non cambiera' proprio piu'.
ivi compresi aggiornamenti del sw a distanza magari di un anno o due.
seno' prova a pensare un debug...
ciao, j.

 impazzisci sull'ordine in cui te li restituisce...
Select * è più lenta di select elenco campi...
hth

 o 20 campi... :)
Vero... d'altra parte quando vai sul pratico molto spesso i campi della
query li specifichi comunque; almeno questo e' quello che facciamo qui... su
query con join *sempre*, su query semplici direi l'80% delle volte, ecco
perche' usiamo in maniera intercambiabile gli indici o i nomi dei campi,
quando siamo in contesti ben controllati.
Il punto e' che la conversione detta sopra non viene fatta dal compilatore
(come potrebbe?), ma suppongo in fase di runtime da ADO o chi per esso, ne
piu' ne meno di come ragionano le collection con le keys... se fosse fatta
*veramente in compilazione* sarebbe una bella ottimizzazione, ma ovviamente
servirebbe un compilatore in grado di comprendere anche il dialetto SQL
Ciao
--
Luca Dormio - 
luca....@tin.it
________________________________
"Marty, non stai ragionando in maniera quadridimensionale"
Dr. Emmett L. Brown

 di tempo......
salve Igor,
per queste evenienze, sarebbe forse piu' appropriata una soluzione del tipo
dim oField as Ado.Field
set oField= oRs.Fields("Descrizione")
with oRs
    while not .eof
        listbox.additem oField.value
        .movenext
    wend
end with
saluti
Andrea Montanari
montanar...@virgilio.it
http://utenti.lycos.it/asql/index.html
(my vb6+sql-dmo little try to provide MS MSDE 1.0 a visual interface) ver
0.0.46
--------- remove DMO to reply

 che ne dici? che ne pensate?
Che sarebbe la fiera del bug.
Usare gli indici al posto dei nomi è da suicidi.
Metti che domani inserisco il campo "P_IVA" prima di "RAGIONE_SOCIALE" devo
ricordarmi che avevo usato gli indici e comunque ricompilare.
Es.: mi è capitato proprio in questi giorni di ristrutturare una tabella che
uso io e un altro programma di terzi.
Dovevo inserire il campo "DataBolla" e ovviamente lo metto subito dopo
"Bolla" e non in fondo alla tabella, tanto dico... "chi è tanto stupido da
usare i campi posizionalmente?".
Inutile dire che il cliente si è trovato il form di inserimento delle bolle
tutto sfasato.
Questo è stupido! Che senso ha dare dei nomi ai campi se poi li uso per
posizione? Tanto valeva che li si potesse inserire solo numericamente, ma
forse si sono accorti che così se due modificano la tabella
contemporaneamente userebbero il campo "n" con scopi diversi... e questo è
anche peggio.
Ciao
--
' // Initialize the expression evaluator
Engines.Evaluator = CreateObject("
http://www.neodatatype.net
")
' // you can find resources for and from the NG here!
Me.SitoComune = "
http://www.it-lang-vb.net
"


[SNIP]
In linea di massima puo' anche essere, ma come sempre, non esiste "LA"
soluzione, solo quella migliore per quel determinato problema, basta sapere
cosa stai facendo...
quante volte hai visto qualcosa del genere?
"SELECT Id FROM TABELLA"
e due righe piu' sotto
Print RS.Fields("Id")
o magari anche
"SELECT Max(Id) AS MaxID FROM TABELLA"
Print RS.Fields("MaxId")
dove un semplice RS.Fields(0) e' piu' che sufficiente, assolutamente
leggibile e sicuro, e ti toglie anche il problema dell'alias... l'importante
e' sapere che si puo' fare in tutti e due i modi, cosa che peraltro nei
libri viene quasi sempre tralasciata...


 leggibile e sicuro,
Dubito fortemente sul leggibile e, per i motivi prima detti (inserimento di
altri campi), anche sul sicuro.
Chi mi impedisce di mettere un campo contatore in coda? Mai usare gli indici
al posto del nome dei campi, nemmeno in fase di ottimizzazione. Esiste il
programma perfetto, cioč non soggetto a modifiche?

 Print RS.Fields("Id")
Vero, ma quante volte scappa il "SELECT *", specie se magari devi escludere
solo uno o due campi dalla select?
E se poi faccio la solita modifica dell'ultimo minuto facendo un bel
"SELECT Pippo, Id FROM TABELLA"?
senza ricordarmi che due righe più sotto avevo (o peggio, qualcun altro)
usato
Print RS.Fields(0)? 'Ricordi? Chi è così stupido da usare gli indici? :)


 End Enum
Anche...
Il punto é un altro...
Ne vale la pena?
Ho fatto 2 prove così, per curiosità...
Private Sub Form_Load()
  Dim cn As ADODB.Connection
  Dim rs As ADODB.Recordset
  Set cn = New Connection
  cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Documents and
Settings\Administrator\Desktop\db1.mdb;Persist Security Info=False"
  Set rs = New ADODB.Recordset
  rs.CacheSize = 1
  rs.Open "SELECT ID, Testo FROM Tab", cn, adOpenForwardOnly,
adLockReadOnly, adCmdText
  Dim Ora As Double
  Ora = Timer
  With Combo
    Do Until rs.EOF
      .AddItem rs!testo
      rs.MoveNext
    Loop
  End With
  MsgBox Timer - Ora
End Sub
Il recordset apre un DB access e carica l'intera tabella (10001 elementi)
1.484875
1.4937
Mentre facendo la stessa cosa con .AddItem rs.fields(1).value
1.3831
1.40096
La differenza di prestazioni é di circa il 7%
Certo non é poco... però non é nemmeno colossale...
Le altre prove: mettendo invisibile la combobox durante il caricamento e
rimettendola visibile dopo il tempo medio sale di circa 5/6 centesimi di
secondo
Usando delle API per il caricamento diretto nella comboBox (metodo molto più
prestazionale) i tempi si riducono a circa 0.6 secondi...
Invece assegnando i valori letti ad una stringa (il che dovrebbe rendere al
massimo l'idea):
Circa 0.190665
Circa 0.161093
Certo la differenza c'é... però... nel 90% dei casi possiamo chiudere
un'occhio... ;)
Alla fine é inutile cercare il pelo nell'uovo su queste cose... sarebbe
meglio ottimizzarne altre ben più pesanti...


 ha scritto nel messaggio
news:Sp8w9.98804$RO.25...@twister1.libero.it...

Hai letto bene il messaggio?
io sto parlando di tutti quei casi in cui viene fatta la select su un campo
secco, a cui si accede comunque per nome, e in ogni caso non confondiamo
l'ordine fisico dei campi in tabella con quello da te imposto in una query,
che non e' la stessa cosa... questo e' quello che intendevo quando parlavo
di "contesti controllati" nel mio primo messaggio.


 Print RS.Fields(0)? 'Ricordi? Chi è così stupido da usare gli indici? :)
Nel caso da te riportato prima, dovremmo correggere in "Chi è così stupido
da usare gli indici con una SELECT * "
Poi ripeto, io preferisco sapere che posso farlo in entrambi i modi... di
queste select a campo singolo ne ho parecchie, e se posso ottimizzarle
leggermente in maniera *assolutamente sicura* non vedo perche' fossilizzarmi
sul "sempre nome, perche' e' meglio"


 *tutta*... e comunque una modifica ad una query non ti "scappa"
hehe, sapevo che lo avresti detto.
Ok, allora diciamo che, come spesso accade, la SELECT sta in un punto,
magari nella Laod e i campi vengano usati un po' sparsi per il codice...
Ovvio, posso controllare tutto il codice, ma il tempo che guadagna il
compilato è paragonabile a quello che perdo io nelle verifiche, magari a
fronte di una consegna urgente?
Per casi come l'altro (es: SELECT SUM(qta) AS Sum_Qta) anch'io uso l'indice
0, ma qui è davvero una select FISSA a campo unico e da usare la riga sotto
e distruggere *2* righe più sotto).
Ciao

 di "contesti controllati" nel mio primo messaggio.
Non ho capito. Vuoi forse dire che la Select viene fatta col nome dei campi
e poi il riferimento agli stessi nel recordset composto come indice?
Se è così la mia obiezione si attenua, ma preferisco comunque far
riferimento ai campi del recset per nome e non per indice (a meno che non
sia un loop su tutti) perchè se devo modificare la Select, sarei costretto
(magari in Sub/Functions nidificate che contano sul, o alle quali si passa
il, recordset) a rinumerare tutti gli indici.

 e poi il riferimento agli stessi nel recordset composto come indice?
[SNIP]
No... il punto e' che la SELECT del mio esempio restituisce tot record ma
con *UN SOLO* campo, non importa che sia Id, Max(), Fava o Favazza; in
questo caso, come dicevo, si puo' tranquillamente usare l'indice senza
perdere ne' in chiarezza, ne' in robustezza... il fatto che non mi detta
preoccupare di verificare altro codice mi deriva anche dalla certezza che, a
mia memoria, non ho un solo punto in cui processo i record in piu' di una
routine (che oltre tutto, raramente e' diversa da quella dove l'ho aperto).
Siamo d'accordo che se aggiungo un campo alla query mi devo porre il
problema, ma appunto qui sto parlando di contesti particolari dove la logica
di accesso ai dati non prevede modifiche del genere (mi vengono tanti
esempi: lista univoca di valori usando DISTINCT, molti usi che si fanno
delle funzioni tipo Max e Sum, select fatte per verificare l'esistenza di un
valore....)


 perdere ne' in chiarezza, ne' in robustezza...
Ora è chiaro, anche se mi capita rarissimamente di _poter_ selezionare un
solo campo.

 valore....)
gia' lo si faceva, appunto con sum ecc.:
    wNBytes = rsSql.Fields(0)
in tutti gli altri casi, ha davvero senso guadagnare due microsecondi
nella compilazione di una query che magari ci mette 10' in esecuzione
?
non certo nella pulizia del codice, che diventa molto piu'
illeggibile. e troppe volte mi e' successo di rimettere mano alla
struttura di un db due anni dopo avere impostato il programma. non oso
pensare se invece di rs!cognome avessi messo rs.fields(2)...
ottimizzando di questo passo, si dovrebbe codificare in assembly...
imho vb e' e resta tutt'altra cosa.
ciao, j.

 end with
Giusto!
Ed é anche molto più prestante...


allora....a parte il fatto che ho scatenato un putiferio stamattina, postano
il primo messaggio......
GIURO, non lo farò mai più, anche se effettivamente ho letto qualcosa di
interessante......
forse la soluzione di Montanari è la più efficiente: in questo modo è più
veloce, dato che la riga incriminata è fuori dal ciclo Do-->While......
Dalla discussione Zanna, Lupo, Dormio salta fuori, secondo me, che la
semplicità del codice mettendo gli indici è veramente nulla, porca
vacca.......


 servirebbe un compilatore in grado di comprendere anche il dialetto SQL
...e di interfacciarsi al database...
Personalmente mi associo a quanti sottolineano la  leggibilità del codice.
Dubito molto che i cicli macchina richiesti dalla traduzione dei nomi campi
possano inficiare _seriamente_ la velocità di runtime della mia
applicazione.
Mi pare che preoccuparsi di questo in un ambiente dove la maggior parte
delle risorse del sistema sono impiegate a gestire icone, sfondi e figurine
varie
sia quasi maniacale...
...cmq, bel thread...
Diversa l'osservazione sulle possibilità di exploit del codice Sql creato a
runtime con concatenazioni di stringhe.
In questo senso, mi associo al buon "lord" sia nel rifiuto netto
dell'oggetto command
sia nella giusta osservazione della necessità di validare i dati inseriti
dall'utente.
Anche in questo caso, tuttavia, è opportuno distinguere tra applicazioni
distribuite
in ambiti (vedi inet) non "controllabili" e applicazioni distribuite in
ambiente aziendale,
dove le possibilità di far danni sono _molto_ più ampie sotto altri punti di
vista
che non nella possibilità di exploit di una Sql runtime: la protezione deve
seguire strade
più significative...
... considerate che di solito inserisco nei programmi un piccolo "Query
analyzer"...
che per altro è molto apprezzato dagli utenti...
ciao
ugo

 analyzer"... che per altro č molto apprezzato dagli utenti...
... considerate che, nel 99% dei casi, non consento all'utente di fare
query, se non utilizzando maschere fatte da me che si occupano di acquisire
"in lingua italiana e non tecnica" le richieste dell'utente e di comporre,
in modo trasparente/nascosto, la query finale nella sintassi SQL, che
l'utente "medio" non capirebbe.

 end with
    Questo sistema ho incominciato ad usarlo un po' di tempo fa con DAO e mi
sono sempre trovato benissimo. Ho notato pero' che e' veramente poco
diffuso. Sbaglio o nelle varie guide ed esempi Microsoft non e' praticamente
mai usato? Opinioni al riguardo?
--
Ciao :-)
Maurizio
--------
?SPQR(C)
 X
--------

Opinioni al riguardo?
Lo uso spesso :-)
-- 
ciao, hal

 Lo uso spesso :-)
scusate se mi attacco qui mi e' sorto un dubbio vedendo che nessuno usa la
mia sintassi correi sapere se c'e' differenza tra usare :
data1.recordset.field("Id")  e  data1.recordset![Id]  ?

 mai usato? Opinioni al riguardo?
Mai usato e mai visto, anche se sintatticamente/stilisticamente è
immediatamente comprensibile. D'acchito, mi è parso un "allungare la strada"
(usare un oggetto che viene ripuntato a un campo del nuovo record corrente
invece di usare direttamente il contenuto del campo stesso), ma ho
verificato: è molto più veloce del classico oRs("Descrizione") o (ma questo
non l'ho verificato) oRs!Descrizione.
Approfitto per correggere un refuso di Andrea: dim oField as ADBDB.Field

 Approfitto per correggere un refuso di Andrea: dim oField as ADBDB.Field
...e io per correggerne uno tuo:
"dim oField as ADODB.Field"    ...     ;-PPPPP
ciao
ugo

 "dim oField as ADODB.Field"    ...     ;-PPPPP
Giuro, stragiuro, che non ho ancora bevuto! ;-))