Newsgroup: it.comp.lang.delphi
Titolo: Uso del ClientDataSet

Ciao a tutti,
volevo sapere se l'utilizzo di Clientdataset tramite un puntatore è 
corretto, oppure mirimane in memoria?
Grazie
function GetCDS(const aSql: string): Pointer;
var
  dst : TSQLDataSet;
  dsp : TDataSetProvider;
  cds : TClientDataSet;
begin
  dst := TSQLDataSet.Create(Self);
  dsp := TDataSetProvider.Create(Self);
  dsp.Name := 'dsp';
  cds := TClientDataSet.Create(Self);
  Try
    dst.SQLConnection := DBXConn;
    dsp.DataSet      := dst;
    cds.ProviderName := dsp.Name;
    dst.CommandText  := aSql;
    cds.Open;
    cds.StoreDefs    := True;
    cds.ProviderName := '';
    dst.Free;
    dsp.Free;
    Result := cds;
  Except
    on E: Exception do begin
      ShowMessage(E.Message);
      Result :=  nil;
    end;
  End;
end;
procedure TForm.Button1Click(Sender: TObject);
var
  cds : TClientDataSet;
begin
  FSql := 'SELECT CAMPO1 from TABELLA where '
        + ' ID =  ' + IntTostr(123) ;
  try
    cds := GetCDS(FSQL);
    //
    if not Assigned(cds) then exit;
    //
    showMessage('Risultato : ' + cds.FieldByName('CAMPO1').AsString);
    //
    cds.Close;
    cds.Free;
    //
  except
   //
  end;
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

     cds := GetCDS(FSQL);
Minimo, servirebbe un cast.
A questo punto però, perchè GetCDS dovrebbe restituire un Pointer
invece di un TClientDataSet?
Saluti
Paolo Arosio

 Paolo Arosio


 Quello che volevo capire se poi con  la close e la free libero la memoria.
La close /probabilmente/ libera delle risorse (cursori, collegamenti
al db, ...) la free invoca il destroy dell'oggetto per cui è chiamata.
Nel tuo esempio invochi tre create e tre free (due la' e una qui).
Saluti
Paolo Arosio

 Il tuo esempio compila?





L'esempio iniziale compila senza problemi su D2007.
Il mio dubbio è solo capire se gli oggetti vengono creati e distrutti in 
modo corretto, x liberare memoria.
Questo perchè poi la funzione Getcds potrei usarla x volte all' interno di 
diverse classi.
Ciò che voglio ottenere è poter "leggere" ( e non aggiornare / aggiungere
/ 
eliminare ) informazioni da un database senza dover avere un datamodule
con 
molti clientdataset.
Sicuramente non è un "modo" carino di scrivere codice, ma in alcuni casi 
aiuta ad ottenere informazioni senza l'ausilio di controlli visuali, ma
solo  
codice all'interno di classi....
Sono disponibile anche ad eventuali suggerimenti.
Grazie ancora.
Ciao Loris
Grazie
Ciao
Loris


> L'esempio iniziale compila senza problemi su D2007.
E come fa a risolvere il pointer in TClientDataset e a capire chi e'
"self" dentro una procedura?
A parte tutto, generalizzi l'apertura del cds  ma poi ti tocca
comunqne specializzarne la lettura..
Ha senso?
A.

 "self" dentro una procedura?
questo non è un problema... posso creare l'oggetto senza owner.
Se hai suggerimenti per migliorare sono pronto x accettarli.
Grazie
Ciao
Loris.


 codice all'interno di classi....
Invece il tuo modo di scrivere codice mi piace, perchè è quasi 
pattern-oriented e sicuramente ti permetterà di risparmiare tempo quando 
dovrai evolverlo o aggiungere altro data retrieving.
Per andare verso una soluzione teoricamente più pulita e coesa, potresti 
dare un'occhio alle teorie dei pattern producer-consumer, o factory builder.
Vale a dire, potresti costruire un sistema tipo producer-consumer, dove 
ogni client£/consumer richiede il suo CDS al producer, e 
quest'ultimoesegue l'SQL, costruisce il CDS e ne ritorna la reference 
possibilmente in readonly (usando const dovrebbe andare).
Attento però che per distruggere il CDS, potresti mantenere la soluzione 
attuale di passare il reference e lasciarlo distruggere al consumer, ma 
questo e' un approccio *debole* perchè separa le logiche di 
allocazione/deallocazione delle risorse.
A questo punto, potresti ottenere un buon compromesso restituendo una 
copia del cds appena creato, e lasciare che sia il consumer a 
distruggerlo quando finito, mentre il tuo producer dopo averlo ricopiato 
lo dealloca e mantiene il DB scarico.
Ti faccio una domanda : se devi usare i CDS solo per prelevare i dati, 
perchè non passare ad una soluzione molto più interessante quale quella 
di usare i cursori monodirezionali? Avresti un aumento delle 
performances non indifferente ed un'ottimizzazione dell'uso del DB.
-- 
morde
D5,D6,D7
QT 4.7.0 - MingW- QT Creator 2.1

 performances non indifferente ed un'ottimizzazione dell'uso del DB.
Anche questa soluzione mi piace molto.....
Come posso applicarla?
Grazie
Ciao
Loris


 Se hai suggerimenti per migliorare sono pronto x accettarli.
Sarebbe meglio usare un framework per la persistenza.
Generalizzare male e' solo di poco meno peggio della spaghetti
programming.
A.


Compila perch� alla fine TClientDataSet � comunque un puntatore.
Ciao.

 Se hai suggerimenti per migliorare sono pronto x accettarli.
Leggere l'help relativo a TComponent.Create.
Ripensare al problema che vuoi risolvere (scusa, ma non ho ancora
capito esattamente quale sia) e riformulare la domanda.
Saluti
Paolo Arosio

 diverse classi.
Mi devo essere perso questo messaggio, sorry.
La risposta al dubbio è "no": li crei con un Owner (che tra l'altro
non passi alla funzione) e poi ne fai la Free.
Questo è *male*.
btw, anche solo creare una classe con il metodo (eventualmente class
method) getCDS sarebbe un bel passo avanti. Uno step intermedio è
creare un datamodule con getCDS. Il datamodule è essenzialmente un
container non visuale per fornire un Owner a componenti non visuali.
Ovviamente l'approccio di morde è ancora oltre :-)
Saluti
Paolo Arosio

 capito esattamente quale sia) e riformulare la domanda.
Forse l'OP ha confuso un pò le cose perchè ha chiesto due hints 
differenti, uno riguardo l'ottimizzazione del codice che fa il passaggio 
dei riferimenti (casting corretti tra consumer/producer) e l'altro per 
capire se la sua soluzione (o generalizzazione) fosse corretta.
ciao


 Come posso applicarla?
Ipotizzo come prerequisito che stai usando ADO e una versione di delphi 
superiore alla 6.
Scrivi una classe CDSProducer che riceve o istanzia una connessione al 
database. Al suo interno, istanzia anche una adoquery.
La classe espone un metodo simile a questo:
getCDSFromSQL(String :query) : TclientDataset;
Al suo interno, costruisci la query usando un cursore forward only, 
dovrebbe aumentare le performances [2].
Una volta eseguita, se la query ha almeno un record la scorri tutta 
aggiungendo tutti i record ad un TClientDataset che avrai creato al 
volo, strutturato in base alle colonne contenute nel recordsert della query.
Chiudi la query e ritorna il CDS appena creato.
Se non ci sono record, restituisci NIL.
Così facendo, scrivi poco codice che fa le cose che servono, e tutti 
chiamano lo stesso metodo.
Ci sono ovviamente delle costraint: chi richiede un CDS è responsabile 
della sua distruzione ed è responsabile dell'integrità della query 
passata. Mantieni così separate le responsabilità ma sopratutto la 
conoscenza: è il chiamante che sa cosa contiene la query, il tuo 
producer non fa altro che eseguire,popolare e ritornare un CDS, senza 
alcuna conoscenza dei dati in esso contenuti.
Chi chiama il producer, non deve neanche sapere qual'è il database, lui 
si vede tornare un CDS e se lo macina come gli pare.
Alcuni punti "weak" di questa architetuttra molto grezza:
1- I dati vengono caricati tutti in memoria prima di essere ritornati: 
questo comporta che per grandi quantità di dati da leggere,la tua 
applicazione si ferma aspettando lo scorrimento completo della query.
2- non dà feedback nel caso succeda un errore sul database (connessione 
perduta, query inconsistente) : in questo caso puoi rimediare aggungendo 
parametri al metodo. Aggiungigli un boolean e una stringa passati come 
reference, se ci sono problemi ritorna false e riempi la stringa con la 
verbosità dell'errore ritornato dal database.
[2] 
http://delphi.about.com/od/database/l/aa061201b.htm
Ciao


 verbosità dell'errore ritornato dal database.
Ottimi suggerimenti.
Grazie 1000.
