PDA

Visualizza la versione completa : [delphi] interbase references 1 a molti


123delphi321
11-05-2004, 14:22
Salve a tutti,

ho un problemino con Interbase,...non riesco ad avere chiara che tecnica utilizzare nella registrazione di tabelle con references 1 a molti.

spiego il problema:

in un programma di fatturazione ho 2 IBtabelle, nella prima registro i valori generali di una fattura quali data, cliente..., nella seconda registro piu record in ognuno dei quali e' un 'articolo' della fattura.

CREATE TABLE MOVIMENTI (
ID_MOVIMENTI INTEGER NOT NULL UNIQUE,
DATA DATE,
CLIENTE VARCHAR(8) NOT NULL REFERENCES CLIENTI (codice) ,
NUMERO_FATTURA VARCHAR(12),
DATA_FATTURA DATE);

CREATE TABLE MOVIMENTI_DETTAGLIO (
ID_MOVIMENTI INTEGER NOT NULL REFERENCES MOVIMENTI(ID_MOVIMENTI),
ARTICOLO VARCHAR(15) NOT NULL REFERENCES ARTICOLI (CODICE),
QUANTITA NUMERIC(9,3),
PREZZO NUMERIC(9,3),
IVA NUMERIC(5,2),
SCONTO NUMERIC(6,2),
NOTE BLOB);

le due tabelle sono collegate tra loro tramite ID_MOVIMENTI,
il mio problema nasce quando devo aggiungere un record nella tabella dettaglio; in quanto e necessario l'assegnazione del ID_MOVIMENTI, ma tale progressivo viene generato nel momento in cui viene confermata la registrazione del movimento principale, cioe quando viene registrata completamente la fattura.

c'e' un metodo x disattivare questo controllo....x poi riattivarlo?

grazie

alka
11-05-2004, 15:32
La soluzione al problema è semplice: devi memorizzare prima la testata ed utilizzare l'ID per specificarlo nelle righe di dettaglio.

Non ha senso, in nessun caso, poter memorizzare un dettaglio senza aver prima inserito una testata. Sarebbe come iniziare a definire i documenti fiscali di un cliente che non è ancora stato inserito nella sezione anagrafica.

123delphi321
11-05-2004, 15:45
...e se poi l'utente nn registra il dettaglio??? devo provvedere io a eliminare la testata dall'archivio? o dovrei lasciare la testata registrata senza alcun dettaglio?

grazie

alka
11-05-2004, 15:58
Originariamente inviato da 123delphi321
...e se poi l'utente nn registra il dettaglio??? devo provvedere io a eliminare la testata dall'archivio? o dovrei lasciare la testata registrata senza alcun dettaglio?
Io non eseguo alcun controllo a riguardo, cioè non forzo l'utente ad inserire dettagli dopo aver definito la testata; ne risulta un documento fiscale sostanzialmente vuoto.

Nella maggior parte dei casi, faccio uso delle transazioni, quindi l'annullamento dell'operazione di inserimento di testata e dettagli di un documento porta all'esecuzione di un Rollback che cancella così sia i dettagli sia la testata.

123delphi321
11-05-2004, 20:00
benissimo ho capito la tecnica.

mi sta succedendo una cosa strana:

una volta ottenuto un dataset con 2 o piu record,...li visualizzo in una dbgrid e li modifico a mio piacimento.

nel momento in cui registro tali modifiche,...ottengo lo stesso numero di record con lo stesso contenuto.

nella dbgrid visualizzo i valori esatti da me variati,...poi premo il tasto per la conferma:

procedure TFrmMovimenti.Button1Click(Sender: TObject);
begin
IBDataSet1.ApplyUpdates;
IBDataSet1.Transaction.CommitRetaining ;
end;
e ottengo N record uguali....

cosa avro' mai sbagliato?...

forse devo aggiungere un progressivo all'interno della tabella dettaglio affinche il record possa essere raggiunto direttamente e identificato univocamente?

mi sapete aiutare? grazie.

alka
11-05-2004, 21:26
Originariamente inviato da 123delphi321
nel momento in cui registro tali modifiche,...ottengo lo stesso numero di record con lo stesso contenuto.
Credo che il tuo problema sia dovuto al fatto che le righe di dettaglio non possiedono un campo chiave. In poche parole, la tabella dei dettagli non ha nemmeno un campo che possa identificare univocamente il singolo record, tranne IDMOVIMENTO che però ha lo stesso valore per tutti i record che appartengono ad un preciso movimento, cioè ad un record contenuto nella tabella primaria, quella con i dati di testata.

Quando invii le modifiche al database server, Delphi cerca di ottenere i dati aggiornati usando un campo chiave, cioè un campo che identifica univocamente il singolo record, per implementare una SELECT e reperirne i dati.

Nel tuo caso, mancando totalmente una chiave primaria, Delphi evidentemente prova con IDMOVIMENTO, ma tutti i record che appartengono ad una certa riga di testata hanno lo stesso valore, perciò per ogni record che Delphi ha a disposizione lato client, reperisce i valori del primo record che viene restituito cercando con un determinato IDMOVIMENTO.

Soluzione: devi introdurre nella tabella secondaria un campo chiave, magari autoincrementale, per garantire che Delphi possa individuare con precisione un singolo record nella tabella.

Osservando la struttura che hai postato in un messaggio precedente, ogni campo può essere duplicato, cioè non esiste una chiave.

In generale, quando devi creare tabelle e metterle in relazione, ma anche in assenza di una relazione (che potrebbe essere costituita "a sorpresa" in un secondo momento), definisce sempre e comunque un campo autoincrementale (tramite generatore) ID che permetta di associare un valore numerico diverso per ogni record di quella tabella.

Poi, se nascono condizioni in cui devi anche impedire che, ad esempio, un documento abbia lo stesso ANNO e NUMERO, allora definisci un indice appropriato, ma non fare a meno di un campo ID autoincrementale che torna sempre utile, anche perchè usando un campo di quel tipo, per ciascuna tabella correlata ti basta usare un solo campo numerico intero per stabilire il legame; in caso contrario, invece, se la coppia di valori ANNO+NUMERO è la chiave primaria all'interno di una tabella, devi introdurre la stessa coppia di campi anche nella tabella secondaria per poter stabilire la relazione; un solo campo non sarebbe sufficiente, dato che un valore di ANNO nella tabella secondaria può legarsi a molti record nella tabella primaria, lo stesso avviene per il campo NUMERO.

Se usi la coppia di campi, allora stabilisci una relazione 1 a molti; se usi un campo ID puoi ottenere più facilmente questo processo e velocizzare i confronti per correlare i record provenienti dalle due tabelle che avverrebbero su un solo campo invece che su 2, magari alfanumerici (quindi ancora più lenti).

Spero di averti chiarito a sufficienza la problematica.

E' più difficile da spiegare che da capire, per la verità, ma posso garantirti che anche gli effetti più strani che a volte ottieni hanno una spiegazione, salvo qualche rara eccezione dove, purtroppo, si tratta di un vero e proprio bug...e anche Delphi ne ha parecchi! ;)

Ciao! :ciauz:

123delphi321
12-05-2004, 09:45
benissimo....capito il problema e l'ho risolto inserendo il progressivo dettaglio.

ma tu che tecnica utilizzi quando l'utente deve inserirwe una nuova Fattura? gli fai premere un tasto NUOVO e in quel momento generi il prograssivo del movimento?


io generavo il progressivo nel momento della registrazione,...solo che adesso devo registrare prima la testata e poi il dettaglio ma vorrei evitare di costringere l'utente a premere 2 volte il tasto di registrazione


grazie

alka
12-05-2004, 09:57
Originariamente inviato da 123delphi321
ma tu che tecnica utilizzi quando l'utente deve inserirwe una nuova Fattura? gli fai premere un tasto NUOVO e in quel momento generi il prograssivo del movimento?
Ho una schermata che visualizza tutte le fatture emesse. Un pulsante "Nuovo" apre una finestra di dialogo modale che richiede l'inserimento della fattura; la parte riguardante la testata è attiva, mentre il corpo del form centrale con i dettagli contiene solo un'indicazione del fatto che occorre salvare la testata prima di procedere all'inserimento dei dettagli. Quando l'utente preme il tasto "Salva", memorizzo i dati di testata con una normalissima Post e rendo operativa la parte visuale relativa ai dettagli, senza chiudere la finestra. L'utente inserisce i dettagli ed esegue il Post attraverso un apposito pulsante; il salvataggio completo avviene con la seconda pressione di "Salva" che implementa la CommitRetaining e chiude la finestra restituendo un esito positivo, affinchè l'elenco delle fatture subisca un aggiornamento.

La generazione del numero progressivo la eseguo sull'evento OnBeforePost del DataSet utilizzato; in questo modo, la versione lato client del record viene dotata del valore dell'ID prima di essere inviata al server; l'ID è senz'altro univoco e corretto poichè restituito sempre dal server. Se il Post va a buon fine, attraverso quell'ID Delphi può reperire con successo i dati appena inviati.


Originariamente inviato da 123delphi321
io generavo il progressivo nel momento della registrazione,...solo che adesso devo registrare prima la testata e poi il dettaglio ma vorrei evitare di costringere l'utente a premere 2 volte il tasto di registrazione
Per una implementazione di questo tipo, credo che l'approccio da seguire, soprattutto se si usano i Data Control, possa diventare parecchio complicato.

123delphi321
12-05-2004, 10:23
La generazione del numero progressivo la eseguo sull'evento OnBeforePost del DataSet utilizzato; in questo modo, la versione lato client del record viene dotata del valore dell'ID prima di essere inviata al server; l'ID è senz'altro univoco e corretto poichè restituito sempre dal server. Se il Post va a buon fine, attraverso quell'ID Delphi può reperire con successo i dati appena inviati.

ma per caricare i dettagli non c'e' bisogno di avere gia ID_TESTATA?

utilizzi due tabelle x testata e dettaglio?

alka
12-05-2004, 10:29
Originariamente inviato da 123delphi321
ma per caricare i dettagli non c'e' bisogno di avere gia ID_TESTATA?
Certo. L'ID della testata viene generato nell'evento OnBeforePost del DataSet che rappresenta la testata e, successivamente, viene utilizzato per i record di dettaglio allo scopo di stabilire la relazione, se il Post della testata va a buon fine.

Quando si crea un nuovo record di dettaglio (evento OnNewRecord) assegno al campo IDTESTATA il valore del campo ID del record di testata inserito e postato in precedenza, mentre per l'ID di dettaglio genero un nuovo valore da assegnare al record sull'evento OnBeforePost, analogamente a quanto avviene per il record di testata.


Originariamente inviato da 123delphi321
utilizzi due tabelle x testata e dettaglio?
Certamente, e c'è un generatore cadauna per poter ottenere, da Delphi, gli ID da assegnare ai record.

Loading