Newsgroup: it.comp.lang.delphi
Titolo: Firebird e AutoInc

Salve,
sto scrivendo un'applicazione in Delphi 6
utilizzando Firebird come motore SQL
cui accedo attraverso i componenti ZEOS.
In una tabella ho un campo autoincrementante.
Non so come fare affinchè, dopo avere eseguito
un Insert dalla mia applicazione, sia possibile vedere
il valore realmente assegnato al campo
autoincrementante lato server dal motore SQL.
Ho impostato i campi statici nel mio componente ZEOS
per l'accesso ad SQL, settando nel caso del campo
autoincrementante la proprietà: "AutoGenerateValue=arAutoInc",
(così come avevo fatto in passato e con successo utilizzando
ADO e un database Access) ma il valore del campo autoincrementante
rimane sempre a zero.
Avete qualche suggerimento in proposito ?
Grazie,
Riccardo
---

Non conosco zeos quindi qualche parte di codice potrebbe non andare.
crei questa sul tuo db:
SET TERM !!
CREATE PROCEDURE MAKE_SOMETABLEID RETURNS (AID INTEGER) AS
BEGIN
   AID = GEN_ID(GEN_SOMETABLE,1;
END!!
Poi, da codice:
procedure TSomeDataModule.MyQueryOnNewRecord(sender: Tdataset);
var
   NewId: integer;
begin
   with spMakeId do
     begin
     ExecProc;
     Id := ParamByname('AId').AsInteger;
     end;
   Dataset.FieldByName('MyFieldId').AsInteger := NewId;
end;
Postilla:
xche impazzire dietro gli autoinc quando una semplice unione di stored 
procedure e generator oltre al vantaggio di rendere il valore visibile 
senza una ulteriore interrogazione del db ti lascia libero di mettere 
nel campo quel che ti pare, cosa che autoinc non fa?
Mica stiamo parlando di m$sql che non ha meccanismi tipo generators e ti 
tocca usare autoinc  e poi chiamare select @@identity, cosa che mi fa 
vo-mi-ta-re.
AS

 end;
Ho capito cosa intendi, ma non credo che faccia al caso mio
perchè sto eseguendo il porting di una applicazione abbastanza
grossa e non posso permettermi di fare una cosa dal genere nel codice
ogni volta che vado a scontrarmi nell'applicazione con un AutoInc.
Vediamo se riesco a trovare una soluzione più immediata.
Comunque grazie mille per il suggerimento
Ciao,
Riccardo
---


 autoincrementante lato server dal motore SQL.
[...]
Quello che generalmente si fa č eseguire una 
SELECT GEN_ID(TuoGeneratore, 1) AS TuoCampo FROM RDB$DATABASE
e usare questo valore per l'INSERT.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 e usare questo valore per l'INSERT.
Ok, grazie ma... ciň significa che non posso in un qualche altro
modo piů immediato scrivere il record sul database (Post),
poi rileggerlo dal server (???), e dunque mettermi in (Edit) ?
Chiedo questo perchč ho una serie di trigger impostati
OnBeforeInsert e vorrei evitare di doverli tradurre in SP
anche perchč cosě facendo dovrei spostare parte della logica
della mia applicazione (il modo con cui vengono calcolati
alcuni campi) direttamente dal server SQL al client Win32.
Scusami se forse dico delle stupidaggini, ma questa č
la mia prima vera esperienza su VERI Server SQL.
Grazie ancora,
Riccardo
---

 ---
-- 
Ciao, Anto', [37, 143, AQ] 
MB C SC 220 CDI Magma Rot
"Di sempre cio' che senti e fai cio' che pensi."
    G.G. Màrquez

     ^^^
Ok, grazie č chiaro il concetto (ed anche il significato del secondo
parametro),
ma io vorrei semplicemente capire cosa devo fare affinchč dopo aver eseguito
in Delphi un'istruzione "DataSet.Insert" (credo necessariamente dopo aver
fatto
il Post, anche se sarebbe preferibile prima per rimanere nello stato
"dsInsert")
sia possibile vedere all'interno dell'applicazione Delphi il valore
assegnato dal
mio server SQL a determinati campi (e non soltanto agli eventuali
autoincrementanti).... ovviamente voglio evitare di fare un refresh
dell'intero
dataset con l'istruzione "DataSet.Refresh"... ho provato con
"DataSet.Resync"
ma non ha funzionato.
Bye,
Riccardo
---

In pratica devo gestire una vendita al banco e
pertanto ho una tabella REG_VBH dove dover
memorizzare i dati degli scontrini emessi.
In questa tabella (REG_VBH), fra gli altri, ci i seguenti campi:
- NumReg: Numero di Registrazione interno (Autoincrementante)
- NumDoc: Numero dello scontrino
- DataDoc: Data e Ora dello scontrino
I campi NumReg e NumDoc sono quelli per cui
sto riscontrando qualche difficoltà.
Infatti, appena eseguo l'insert di uno scontrino dalla
mia applicazione in Delphi vorrei poter vedere:
1) Il NumReg autoincrementante generato dal server Firebird SQL
2) Il numero di scontrino calcolato dal server Firebird SQL
in funzione del campo Data.
Le soluzioni al momento trovate sono:
1) Effettuare un'istruzione SQL del tipo:
    SELECT GEN_ID(Gen_NumReg, 1) AS NumReg FROM RDB$DATABASE
e poi, in Delphi, assegnare il valore restituito al
REG_VBH.FieldByName('NumReg')
in modo da gestire direttamente dall'applicazione client l'incremento del
Generator.
2) Effettuare un'istruzione SQL parametrizzata del tipo:
  SELECT CAST(MAX(NUMDOC) AS INTEGER)+1 FROM REG_VBH
  WHERE (CAST(DATADOC AS DATE) = :DATA)
  INTO :NUMDOC;
Inizialmente avevo implementato la soluzione 2) all'interno di un trigger
OnBeforeInsert
in modo che subito prima di memorizzare il record venisse calcolato il
numero scontrino,
ma questo (come nel caso del campo NumReg autoincrementante) non mi
permetteva
di visualizzare in tempo reale dalla mia applicazione Delphi l'effettivo
numero assegnato
dal server SQL allo scontrino (ovvero il valore di NumDoc).
Successivamente, per i motivi suddetti, ho scritto un'apposita Stored
Procedure che
richiamata da Delphi mi restituisse il numero dello scontrino (NumDoc) in
modo da
poter assegnare tale valore al campo NumDoc direttamente sul lato client
ovvero
tramite l'applicazione in Delphi, così facendo però sorge un problema ovvero
che
lavorando in multiutenza potrebbe capitare che due postazioni X e Y
utilizzino lo
stesso numero di scontrino:
- X richiama la stored procedure ed ottiene il valore K da assegnare a
NumDOC
- Y richiama la stored procedure ed ottiene il valore K da assegnare a
NumDOC
- Entrambe X e Y in qualunque ordine confermano la registrazione dello
scontrino
  e così si ha che esisteranno due diversi scontrini emessi lo stesso giorno
da due
postazioni diverse X e Y che però hanno lo stesso numero di scontrino K.
Soluzioni diverse da proporre ?
Grazie,
Riccardo
---

 in questo modo dovresti avere il valore che verra assegnato al tuo id
Anto', questo sistema ha una grossa falla.
Cosa suucede nel caso di 2 o piů operazioni di inserimento simultanee?
Non puoi avere la certezza che quello restituito da quella formula siae 
l'ultimo id calcolato da TE e non da altri client.
Per risolvere questo problema, la select @@identity di m$Ssql 
restituisce l'ultimo autoinc calcolato nella sessione attiva.
Bye
AS

 autoincrementanti).... ovviamente voglio evitare di fare un refresh
non hai modo di farlo xche il client di quel valore non sa nulla: è 
tutto fatto lato server, compreso il caso in cui l'id viene calcolato ed 
assegnato da un trigger.
Questo è il motivo per cui odio usare trigger e/o autoinc per calcolare 
chiavi primarie, sopratutto l'autoinc che ti vincola troppo.
Tutto ovviamente e rigorosamente imho.
AS

 postazioni diverse X e Y che perň hanno lo stesso numero di scontrino K.
se usi un generator questo non accade.
Bye
AS

 se usi un generator questo non accade.
Sì, lo so... ma non posso usare un generator perchè
se da una postazione viene annullato uno scontrino in fase
di emissione è necessario che non rimanga un vuoto nella
serie numerica degli scontrini.
Esempio:
- Sono stati già emessi gli scontrini 1,2,3,4
- A sta emettendo lo scontrino 5
- B sta emettendo lo scontrino 6
- A annulla lo scontrino 5
- B conferma lo scontrino 6
La serie numerica degli scontrini diventa 1,2,3,4,6....
ovviamente manca lo scontrino n.5, e questo non è
accettabile per la mia applicazione.
Ciao,
Riccardo
---

 
Mi chiedo: a può annullare lo scontrino dopo che è stato emesso?
Se la risposta è no, potrebbe essere sufficiente spostare la 
assegnazione dell'id con il generator dall'evento OnNewRecord all'evento 
  BeforeUpdate, nel quale fai un check:
se il dataset è in insert mode, allora esegui la stored procedure che 
calcola l'id tramite il generator e assegnalo al relativo campo del db.
In questo modo l'id viene generato solo se l'utente conferma l'operazione.
Ma se poi il numero di scontrino deve essere azzerato a fine anno per 
ripartire da 1, allora, imho, la tabella di contatori puo fare al caso tuo.
AS

 ripartire da 1, allora, imho, la tabella di contatori puo fare al caso
tuo.
Il numero di scontrino riparte sempre da 1 quotidianamente, ovvero è
una numerazione progressiva all'interno dello stesso giorno.
"Tabella di contatori" ? Intendi "Generator" ?
Ciao e Grazie,
Riccardo.

 
La cosa mi interessa molto, in quanto a breve devo fare anche io una
similie applicazione ma per l'emissione di fatture (evitando
chiaramente una numerazione doppia).
Io ipotizzavo di "disabilitare" l'immissione di una fattura da tutti
le postazione di lavoro se un utente aveva iniziato l'inserimento e di
"abilitare" l'emissione non appena il nuovo record è stato scritto sul
server. Questo perchè io non posso sapere se l'utente in questione
memorizza o meno la fattura: potrebbe annullare il suo inserimento, e
in questo caso una qualiasi gestione di numerazione andrebbe a farsi
friggere! Ma ancora non ho scritto neppure un riga di programma in
merito!
Sarebbe anche interessante avvisare l'utente che era disabilitato
all'inserimento, che è nuovamente abilitato a farlo.
Se ci notizie o idee in merito, fammi sapere, grazie.