Newsgroup: it.comp.lang.delphi
Titolo: Delphi 2005 + DbGo: casting forzato dei parametri di una query

Effettuando le mie prime prove con Delphi 2005 (edizione pro) ho notato 
una cosa simpatica.
Nella quasi totalità delle applicazioni che sviluppo uso database 
Microsoft, spec. MSDE, e finora con somma gioia mi sono sempre 
appoggiato ai DbGo.
Siccome sto muovendo i primi passi con D2005, volevo fare qualche 
esperimento ricostruendo un qualche programma su .Net, usando ovviamente 
i componenti VCL.Net
In particolare ho notato questa cosuccia: ammettiamo di avere una 
tabella di anagrafica di clienti e fornitori, differenziati dal campo 
tipoclientefornitore, e di voler selezionare tutti i clienti. Volendo 
impostare tutto via codice scriverei:
 
	ADOQuery1.Close;
	ADOQuery1.SQL.Clear;
	ADOQuery1.SQL.Add('select *');
	ADOQuery1.SQL.Add('from ANAGRAFICACLIENTIFORNITORI');
	ADOQuery1.SQL.Add('where tipoclientefornitore = :tipo');
	ADOQuery1.Parameters.ParamByName('tipo').Value := 'C';
	ADOQuery1.Open;
Ebbene: tutto ciò non funziona, ovvero nella query non viene caricato 
/*niente*/. Se invece carico a mano il testo nell'oggetto e valorizzo 
visualmente il parameter della collection Parameters, specificandone 
prima il tipo, il tutto funziona.
Siccome talvolta mi capita di dover impostare tutto via codice e siccome 
l'esempio indicato ha sempre funzionato, da Delphi 5 a Delphi 7, la cosa 
mi alterava un attimo. Allora ho provato ad indicare esplicitamente 
anche il cast e tutto è tornato normale:
	ADOQuery1.Parameters.ParamByName('tipo').Value := String('C');
	ADOQuery1.Open;
Che dite? Parrebbe che l'ambiente non trasformi il variant Value in un 
tipo standard in modo diretto, ma che occorra esplicitarlo...
Se qualcuno aveva notato lo stesso problema e ha notizie in merito, 
sarebbe bello approfondire...
	Marco Bortolani
	info @ 
marcobortolani.it
P.S.
Di solito non uso impostare a True la property Prepared prima di 
valorizzare i parametri, ma comunque la cosa non incide: ho provato a 
farlo e non funziona lo stesso.

 tipo standard in modo diretto, ma che occorra esplicitarlo...
Provo a lanciare qualche ipotesi...
Da quanto ho potuto apprendere su 
VCL.NET
, si tratta di una libreria 
davvero interessante perchè non è semplicemente un porting su 
compilatore Delphi.NET della libreria Win32 classica, ma è una libreria 
completamente alternativa a Windows Forms che consente di portare molto 
codice già scritto per le applicazioni precedenti ma, di fatto, è 
estremamente integrata nella gerarchia delle classi base del framework.
Questa introduzione è necessaria per spiegare che, prendendo in esame 
proprio il caso dei Variant, molto codice esistente che supporta questo 
tipo di dati può essere trasportato in .NET senza problemi poichè, a 
livello logico, le funzioni 
VCL.NET
 consentono di farlo ma, scendendo a 
basso livello, il Variant come era conosciuto in Win32 non è più lo 
stesso, poichè non ha nemmeno molto senso di esistere nel mondo .NET.
Infatti, se vai a cercare la dichiarazione del tipo Variant nel codice 
della libreria 
VCL.NET
 scoprirai che è un tipo equivalente a TObject, 
che poi è un alias per *System.Object*, la classe base da cui derivano 
tutti i tipi utilizzati dai linguaggi che hanno un compilatore .NET.
Partendo da questo presupposto, secondo me il tuo codice iniziale
   ADOQuery1.Parameters.ParamByName('tipo').Value := 'C';
fa in modo che quel parametro venga valorizzato con un'istanza di 
*System.Char* contenente il valore 'C', il quale probabilmente non è 
valido o non ottiene lo stesso risultato di
   ADOQuery1.Parameters.ParamByName('tipo').Value := String('C');
oppure
   ADOQuery1.Parameters.ParamByName('tipo').Value := System.String('C');
dove espliciti che la proprietà /Value/ di tipo Variant, che poi non è 
altro che un oggetto *Object*, fa riferimento ad un dato di tipo 
*System.String* composto da un solo carattere che è "C".
Si tratta però solo di una mia supposizione, non ho il tempo materiale 
per approfondire in questo momento ma lo farò senz'altro il prima 
possibile. :-)
Ciao,
   Marco.
-- 
Marco «Alka» Breveglieri	
http://www.marco.breveglieri.name
  «bvmcnxsjlkhròhyeq, potrei scrivere a questo punto,
   se mi addormentassi sui tasti» (Daniele Luttazzi)

 possibile. :-)
Anche secondo me varrà la pena tenere d'occhio questa cosa, in 
particolar modo perchè intacca un mio modo di scrivere il codice, che 
quindi alla vecchia maniera semplicemente non funzionerebbe :-(
	Marco
	info @ 
marcobortolani.it

Marco Bortolani ha scritto:
 > Perchè secondo te non hanno senso i variant nel framework? Un variant è
 > un tipo-non tipo, ovvero una variabile di tipo variant può contenere
 > valori di specie diverse, come numeri o stringhe...
Mi sono spiegato male: non è che non abbiano senso, ma essendo qualsiasi 
tipo di dato derivato da *System.Object*, è sufficiente usare questo 
tipo per dichiarare una variabile che può, opzionalmente, puntare ad un 
dato di qualsiasi tipo, come sembrerebbe avvenire in 
VCL.NET
.
 > Anche secondo me varrà la pena tenere d'occhio questa cosa, in
 > particolar modo perchè intacca un mio modo di scrivere il codice, che
 > quindi alla vecchia maniera semplicemente non funzionerebbe :-(
Forse quello è un caso particolare, un'ambiguità derivante dal fatto che 
usi un letterale composto solamente da uno solo carattere, che quindi 
confonde il compilatore.
Non sono però sicuro di aver colto davvero nel segno: per fare la prova, 
basterebbe verificare qual è il valore di
   ADOQuery.Parameters.ParamByName('...').Value.GetType.ToString
(sempre se ho scritto bene la sintassi a memoria.


   ADOQuery.Parameters.ParamByName('...').Value.GetType.ToString
Si tratta di System.String sia nel caso di cast implicito del valore 'C' 
che in quello di cast esplicito, ma nel primo caso la query non ritorna 
alcunchè.
	Marco
	info @ 
marcobortolani.it

 alcunchè.
Azz...si tratta sempre di *System.String*?
Strano... Indagherò... ;-)


 
Ho fatto un'altra simpatica prova: nella mia fantastica query ho provato 
a prelevare il valore del parametro da un campo di Edit invece che 
esplicitandolo. Ho scoperto così che anche se scrivo solo C nel campo ed 
eseguo la query, questa funziona alla perfezione.
Il sunto quindi parrebbe essere che una roba del tipo
	ADOQuery1.Parameters.ParamByName('tipo').Value := 'C';
non comporti internamente alcun cast automatico, mentre
	ADOQuery1.Parameters.ParamByName('tipo').Value := Edit1.Text;
comunichi al motore database le informazioni corrette.
Ho fatto questa prova perchè mi sono ricordato di quando sviluppo le 
pagine ASP su un server IIS in italiano e mi serve fare una query in 
base ad una data: perchè la query vada, mi tocca formattare la data 
parametro in formato americano se il giorno è minore di 12 ed in formato 
europeo dal 13 in avanti.
Non volevo dover validare l'input dell'utente e controllare quanti 
caratteri ha messo tutte le volte...
	M.
P.S.
Quante cose sto scoprendo già dal primo giorno :-)

 europeo dal 13 in avanti.
ASP.NET
, o meglio 
ADO.NET
, supporta pienamente le query parametriche, 
pertanto le pagine 
ASP.NET
 non risentono di questo problema.
O forse non ho capito...? :-/
Ciao,
   Marco.


 
No, no: hai capito giusto, con le query parametriche il problema della 
conversione non l'avrei avuto :-))
	M.