Newsgroup: it.comp.lang.delphi
Titolo: TClientDataSet e inserimento di record con primary key autoincrementante

Salve,
ho appena iniziato a lavorare con dbexpress in Delphi 2010 e ho un bel 
po' di problemini.
Come db uso Firebird.
Ho definito una base dati con una tabella  con campi Index e Name in cui 
la chiave Index e` generata automaticamente tramite generator e trigger.
Quando provo ad inserire un record, se non assegno un valore a Index e 
chiamo ClientDataSet.Insert ottengo un errore (assenza di un valore 
richiesto)... evidentemente manca il valore Index ma non so come 
collegare il generator del db al clientdataset.
Come faccio ad inserire da delphi un record nella tabella? Posso usare 
ClientDataSet o devo scendere a SQLDataSet e definire un SQL statement?
ClientDataSet ha accesso ai valori del generator nel database?
E gia` che ci sono... sapete dove trovare una buona documentazione su 
dbexpress?
Enrico

 dbexpress?
imho, non c'e' molto da sapere.....
Occorre solo ricordarsi che gli oggetti query sono UNIDIREZIONALI.
Questa cosa che per i furbi di cui sopra  rende dbx INUTILE e' legato
al fatto che non puoi attarcali via datasource a conrolli dbaware come
una dbgrid.
E a questi furbi dovrebbe essere vietato per legge anche programmare
il cronotermostato di casa loro...
A.

 collegare il generator del db al clientdataset.
Lavorando con il componente "TClientDataSet" e con dbExpress, credo che 
la scelta meno dolorosa e più efficace sia quella di etichettare il 
record con il suo ID autoincrementale lato client Delphi prima di 
andarlo a memorizzare nella tabella; in questo modo, l'applicazione 
conosce già l'ID applicato e può usarlo per ricercare da subito il 
record, una volta inserito, per ottenere eventuali campi calcolati, 
modificati da trigger e così via, avendo a disposizione una "chiave 
sicura" con cui indirizzare il record appena inserito.
Generalmente io procedo così: creo una vista o una stored procedure sul 
database che restituisca il valore del generatore (con l'istruzione 
GEN_ID) all'applicazione Delphi, che provvede ad appiccicarlo al record 
prima dell'effettivo inserimento su DB.
Ciao,
   Marco.
-- 
MARCO BREVEGLIERI
  (
http://www.marco.breveglieri.name
)

Ho risolto con un generatore, un trigger e una query.
Quindi l'applicazione non vede assolutamente il valore del generatore al 
momento dell'inserimento.
Soltanto dopo un refresh del ClientDataSet ho accesso al nuovo record 
(dove posso vedere il valore assegnato dal generatore).
Grazie per i consigli
Enrico
W dniu 2010-12-04 15:15, Marco Breveglieri pisze:


 (dove posso vedere il valore assegnato dal generatore).
..e come lo trovi il *nuovo* tra gli n del cds..?
A.


Nel caso specifico mi interessa solo inserire un nuovo valore nella tabella.
Uso poi i record della tabella in un lookup...

 (dove posso vedere il valore assegnato dal generatore).
Io però te lo sconsiglio, perché così devi aggiornare inutilmente 
l'intera tabella per poter avere il nuovo record, mentre sarebbe 
sufficiente "appiccicare" l'ID al record prima dell'inserimento nel 
database per aggiornare automaticamente solo e soltanto il nuovo record 
lato client attraverso la sua chiave (l'ID assegnato, appunto).



Se chiedo al db l'ID e poi inserisco il record con il db ottenuto corro 
il rischio di un conflitto se un altro utente esegue la stessa 
operazione fra la richiesta dell' id e l'inserimento del record.
Come risolvi questo tipo di problemi?
Potrei chiedere l' id e contemporanemaente incrementare il suo valore 
nel db...
Che tecniche usate in questi casi?
A presto
Enrico

 operazione fra la richiesta dell' id e l'inserimento del record.
..scusa, ma come fa un generator a darti 2 volte lo stesso valore?
A.

 Come risolvi questo tipo di problemi?
problema vecchio quanto il mondo, affrontato centinaia di volte in 
questi anni su icld... il bello è che non esiste la soluzione perfetta: 
si cerca di evitare la concorrenza spostando lato database la 
generazione dell'ID.
io uso un trigger sull'evento before insert di un record.
Esempio di script DDL:
SET TERM ^ ;
CREATE TRIGGER BI_WI_REGOLE_TAT_ID FOR WI_REGOLE_TAT ACTIVE
BEFORE INSERT POSITION 0
AS
BEGIN
   IF (
NEW.ID
 IS NULL) THEN
 
NEW.ID
 = GEN_ID(WI_REGOLE_TAT_ID_GEN, 1);
END^
SET TERM ; ^
In pratica, prima di inserire un record nuovo nel database, il database 
stesso esegue questo trigger e nella colonna ID del record che sta per 
scrivere inserisce un ID nuovo generato dal generatore WI_REGOLE_TAT_ID_GEN.
In questo modo, non avrai mai due ID identici. Al limite, se andrai a 
rollbackare qualche insert, otterrai dei buchi nella sequenza degli ID, 
ma gli ID servono a fare da riferimento unico del record e quindi vai 
bene così.
Ah, una volta ho letto che qualcuno usa gli ID come numeratori dei 
documenti: orribile.. non mischiare mai queste due cose o sarai 
costretto a gestire/riciclare i buchi della sequenza di ID generati dal 
generator... in altre parole: follia.
ciao
-- 
morde
D5,D6,D7
QT 4.7.0 - MingW- QT Creator 2.1

 operazione fra la richiesta dell' id e l'inserimento del record.
No. Se usi un "generatore", l'ottenimento di ID univoci da questo è 
garantito, anche e soprattutto in ambito multiutenza: è fatto apposta. :)



E` esattamente quello che faccio io.
Gia che siamo sull' argomento, cosa mettete ancora negli script ddl?
Sto pensando di creare quanti piu` possibili script per inserimento, 
edit e estrazione di dati in modo da diminuire il passaggio di dati e 
semplificare l'applicazione client.
Ciao
Enrico

 A.
Pensavo di fare l'incremento del generatore solo al momento dell' 
inserimento del record.
Quindi fra la richiesta del valore del generatore e l'inserimento del 
record (con incremento del generator) ci sarebbe la possibilita` che un 
altro utente faccia lo stesso causando un conflitto.
Comunque posso incrementare (come anche ha suggerito morde) il generator 
ogni volta che faccio una richiesta del suo valore attuale, 
eventualmente sprecando uno dei valori del generator nel caso l' utente 
decida poi di non inserire il record.
Enrico

 semplificare l'applicazione client.
Non è una cattiva idea: in passato ho lavorato in un posto dove il 
gestionale demandava tutta la logica CRUD [1] a stored procedure.
Al software non restava che recuparare i dati.
[1] 
http://en.wikipedia.org/wiki/Create,_read,_update_and_delete
