Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 12
  1. #1

    [delphi] gestire errori sul Database

    Salve a tutti. ho creato una piccola applicazione con Firebird e i componenti DBExpress di Delphi. L'applicazione non usa una chiave primaria con incremento autoamatico (me l'hanno chiesto così :-\). Ho cercato di gestire l'errore generato nell'inserimento di una chiave primaria duplicata. Ho scritto un evento OnPostError del componente ClientDAtaset e nessun problema... tutto ok:-). Mi manda un messaggio di errore, non inserisce il nuovo record creato in quanto ha una chiave già utilizzata (uso il metodo RevertRecord del ClientDataset per cancellarlo) e tutto va bene.

    Il problema mi nasce quando copio le librerie e il programma compilato su una cartella utilizzando Firebird embedded. Praticamente non mi genera l'errore e inserisce nel Dataset il record con la chiave duplicata. Mi spiego meglio. Avendo inserito i classici componenti di visualizzazione (DBEDIT, DBGRID ecc) il record viene inserito nella tabella ma non nel database (immagino che il metodo upplyupdate fallisca). Ma questo nonv a bene nella mia applicazione che dovrebbe comportarsi come in fase di progetto.

    Qualcuno può aiutarmi?

    Ringrazio anticipatamente.

  2. #2
    non puoi inserire una query a run-time (utilizzando una TQuery)?
    select chiave_primaria from mia_tabella where chiave_primaria="mio_inserimento";

    se il result set è vuoto allora la chiave non esiste e la inserisce, se invece il result set contiene un elemento gestisci secondo quello che la tua applicazione prevede.
    ciao
    sergio

  3. #3

    Grazie della risposta

    Ti ringrazio della risposta . ci avevo pensato anche io, ma in effetti preferirei catturare gli errori che mi manda il database...

    volevo sapere come mai la versione firebird embedded mi da questgo inconveniente, se si deve fare qualche settaggio che non ho fatto (ma non credo) o se sbaglio qualcosa io

    Ti ringrazio della risposta


  4. #4
    mi spiace, non ti saprei dire perché di regola utilizzo mysql.
    Potrebbe anche essere un baco.
    ciao
    sergio

  5. #5
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,472
    Il problema è logico e deriva da un utilizzo errato dei componenti.

    Il componente TClientDataSet rappresenta un DataSet in memoria, e quindi inserire record all'interno del database solo quando viene invocato il metodo ApplyUpdates.

    Quindi, se un record non deve essere inserito nel DB, l'invocazione del metodo fallirà, ma l'inserimento va a buon fine in quanto il TClientDataSet non si porta dietro le regole che esistono lato server.

    Non credo, in sostanza, che sia un problema dovuto alla versione di FireBird in uso, ma bensì ad un caso di utilizzo che, per coincidenza, è stato incontrato nell'ambito della versione Embedded ma che dovrebbe essere facilmente riproducibile anche con qualsiasi altra versione.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  6. #6

    Grazie

    Ti ringrazio della risposta... sei stato molto gentile

    ti faccio sapere..

    Ciao

  7. #7

    Ciao

    Ciao Alka, approfitto della tua gentilezza ti scrivo una parte di codice:

    procedure TForm1.ClientDataSet1PostError(DataSet: TDataSet;
    E: EDatabaseError; var Action: TDataAction);
    begin
    ShowMessage('Errore'');
    Action := daAbort;

    ClientDataSet1.RevertRecord;

    end;


    sbaglio qualcosa?

    Ho fatto delle prove:

    In fase di progettazione (utlizzando il server Firebird) mi da l'errore ed elimina l'operazione eseguita cancellando il record.

    Quando lo compilo ed inserisco il file exe e la libreria di Firebird embedded in una cartella(fermando il server Firebird) e lo rinomino in gds32.dll non mi da l'errore e non cancella il record.

    Se elimino la libreria gds32.dll e faccio ripartire il server Firebird ed uso naturalmente la versione compilata mi da l'errore ed elimina l'operazione eseguita cancellando il record.


    forse sn fuori strada?

    grazie e scusa l'insistenza


  8. #8
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,472

    Re: Ciao

    Originariamente inviato da Brendon77
    sbaglio qualcosa?
    Dipende: qual è la tua intenzione?

    Originariamente inviato da Brendon77
    In fase di progettazione (utlizzando il server Firebird) mi da l'errore ed elimina l'operazione eseguita cancellando il record.
    In fase di progettazione, non hai la possibilità di cancellare sostanzialmente alcun record.
    A cosa ti riferisci?

    Originariamente inviato da Brendon77
    Quando lo compilo ed inserisco il file exe e la libreria di Firebird embedded in una cartella(fermando il server Firebird) e lo rinomino in gds32.dll non mi da l'errore e non cancella il record.
    Se parli di FireBird Embedded non vedo perché dovresti arrestare il server FireBird, visto che questo non viene interrogato dalla libreria (proprio perché è "embedded").

    Sull'errore che non ti dà... qual è l'errore che dovrebbe darti?
    Perché rinomini il file della libreria?
    E poi, quali componenti stai utilizzando per accedere al database?

    Originariamente inviato da Brendon77
    Se elimino la libreria gds32.dll e faccio ripartire il server Firebird ed uso naturalmente la versione compilata mi da l'errore ed elimina l'operazione eseguita cancellando il record.
    Cosa vuol dire "uso la versione compilata"? Tutti i programmi Delphi che lanci sono compilati.

    Originariamente inviato da Brendon77
    forse sn fuori strada?
    Diciamo che oltre ad esserci parecchia confusione, non mi è chiaro nel modo più assoluto ciò che stai cercando di fare, come è organizzato il progetto, il motivo per cui avvii e arresti continuamente il server e rinomini le librerie esterne. Penso di averle elencate tutte.
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

  9. #9

    right :-)

    Cerco di essere più chiaro...

    Ho sviluppato questa piccola applicazione utilizzando

    SQLDATASET -> DATASETPROVIDER -> CLIENTDATASET

    in questa applicazione la chiave primaria deve essere inserita manualmente (di solito preferisco crearla autoincrementante ma me l'hanno chiesta così), sorge inevitabile un controllo sulla stessa.

    Naturalmente, nel momento che si cerca di inserire una chiave primaria già presente, il metodo "ApplyUpdate" fallisce, viene lanciata l'eccezione e il record viene però inserito lo stesso, non fisicamente sul Database ma in memoria, siccome il componente CLIENTDATASET opera proprio in memoria. Questo è un comportamento normale. Ho deciso allora di scrivere un evento "OnPostError" del CLIENTDATASET in modo da gestire l'errore (sempre in memoria).

    procedure TForm1.ClientDataSet1PostError(DataSet: TDataSet; E: EDatabaseError; var Action: TDataAction);
    begin
    ShowMessage('Errore sull'inserimento'');
    Action := daAbort;

    ClientDataSet1.RevertRecord;
    end;

    In questo modo, lancio un messaggio di errore (siccome la chiamata al metodo UpplyUpdate fallisce) e con il metodo:

    "ClientDataSet1.RevertRecord;"

    faccio in modo di tornare alla situazione in memoria prima della chiamata di UpplyUpdate

    In questo modo, non solo viene avvertito l'utente che un errore è stato generato (in questo caso la chiave primaria duplicata), ma evita di scrivere nel ClientDataset il nuovo record che sarebbe inesatto siccome avrebbe una chiave primaria già utlizzata.

    Stiamo sempre parlando di memoria poichè, a priori, come è logico che sia il Database non inserisce mai il record con la chiave primaria duplicata e questo è il comporamento che ci si aspetta.

    Il problema era gestire il ClientDataset che opera in memoria e credevo di avercela fatta.

    Le prove che ho fatto, forse le ho scritte in modo confusionale, sono dettate dal fatto che, dopo averci sbattuto la testa e non riuscendo a capire, mi sono reso conto che l'errore me lo dava Firebird Embedded ma non ne ero sicuro così ho chiesto aiuto (è la prima volta che utilizzo Firebird in generale).

    Per la mia applicazione ho utilizzato la versione "non embedded". Tutte le applicazioni Delphi sono naturalmente compilate, ma come avevo detto, ho copiato tutte le librerie e il file EXE in una cartella esterna per verificare il funzionamento della versione embedded su un altro PC... lo scopo era proprio questo . Far funzionare l'applicazione su un computer su cui non era installato Firebrid e capire come funzionava la versione Embedded.

    Dalla documentazione di Firebird ho letto che dovevo rinominare la libreria

    "fbembed.dll" in ""gds32.dll"

    Tutto andò bene, su un altro pc(senza server firebird) il programma funziona correttamente tranne per un cosa.....
    nell'inserimento di una chiave primaria già utilizzata non compare il mio mesasggio di errore personale e in più viene inserito il record corrispondente (sempre in memoria.... nel database non ci sono modifiche).

    Ho provato allora a cercare l'errore e da qui il mio continuo fermare e attivare il server. Magari era inutile ma volevo essere sicuro.

    Praticamente il comportamento da me progettato e sperato (l'invio del mio messaggio di errore e non inserimento del record me lo da se utilizzo il server Firebird)... se provo ad utilizzare la versione embedded ecco che tutto non funziona....

    Penso di essere stato + chiaro e preciso....

    Immagino che sia inutile fermare il server firebird se in una cartella c'è già la libreira del Firebird Embedded, penso che venga vista prima lei, ma volevo essere sicuro per avere la certezza....

    Magari tutto dipende da un errore mio di progettazione non so....

    Ringrazio per l'attenzione e per l'aiuto...

    Ciao

  10. #10
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,472

    Re: right :-)

    Originariamente inviato da Brendon77
    in questa applicazione la chiave primaria deve essere inserita manualmente (di solito preferisco crearla autoincrementante ma me l'hanno chiesta così), sorge inevitabile un controllo sulla stessa.
    Che venga inserita dall'utente, o che venga creata automaticamente, il campo chiave deve essere sempre attribuito al record prima di salvarlo all'interno del ClientDataSet, poiché questo consente al componente di aggiornare tale record dopo averlo inserito, se inesistente, nel database sottostante. Nel caso di campi autoincrementali, il valore va prelevato usando un apposita stored o un apposito strumento, come i "generatori" in FireBird, e attribuito al record prima di salvarlo.

    Originariamente inviato da Brendon77
    Naturalmente, nel momento che si cerca di inserire una chiave primaria già presente, il metodo "ApplyUpdate" fallisce, viene lanciata l'eccezione e il record viene però inserito lo stesso, non fisicamente sul Database ma in memoria, siccome il componente CLIENTDATASET opera proprio in memoria.
    E questo è il primo problema: il ClientDataSet dovrebbe avere ottenuto i record dal database, a cui vai aggiungere nuovi record da salvare successivamente chiamando ApplyUpdates.

    E' necessario impostare un campo come chiave per evitare che il record venga inserito nel CDS se la chiave è duplicata, senza attendere il momento in cui questo verrà inviato al server.

    Originariamente inviato da Brendon77
    Questo è un comportamento normale.
    Non è un comportamento normale, o meglio lo è se il componente CDS non è configurato correttamente. Definisci un indice sul componente CDS usando la proprietà IndexDefs e assegnandogli l'attributo di univocità, oltreché facendolo riferire al campo chiave.

    Originariamente inviato da Brendon77
    Ho deciso allora di scrivere un evento "OnPostError" del CLIENTDATASET in modo da gestire l'errore (sempre in memoria).
    Quell'evento viene generato nel momento in cui il Post di un record nel CDS fallisce.
    Il problema è dato dal fatto che se non vi è da alcuna parte una condizione che fa fallire l'operazione, l'evento non viene mai generato. Se inserisci un record con chiave duplicata in memoria e non c'è nulla che verifica questa condizione, non si verificherà nemmeno l'errore relativo e quindi l'evento OnPostError, generato quando si verifica un'eccezione, non verrà mai eseguito.

    In sostanza, il CDS accetta qualsiasi record di buon grado, almeno fino a quando questi rimangono in memoria.

    Originariamente inviato da Brendon77
    In questo modo, lancio un messaggio di errore (siccome la chiamata al metodo UpplyUpdate fallisce) e con il metodo:
    "ClientDataSet1.RevertRecord;"
    faccio in modo di tornare alla situazione in memoria prima della chiamata di UpplyUpdate
    Questo non è vero. Quando invochi ApplyUpdates, salvi sul DB le modifiche apportate ai record nel CDS (inserimenti, aggiornamenti, cancellazioni): queste modifiche a livello di CDS sono definitive e confermate. Se ApplyUpdates fallisce, tali record rimarranno nel CDS, solo non verrà aggiornata la base dati sottostante (in questo caso, tocca allo sviluppatore prendere provvedimenti per correggere i record).

    Se invochi la RevertRecord, non fai altro che annullare le modifiche all'ultimo record nel caso in cui tu non riesca a salvare sul DB tutte le modifiche apportate a quello e ad altri record eventualmente presenti. E' un po' come se io scrivessi una riga di dati e, a causa di un campo non corretto, mi venissero annullate tutte le modifiche apportate, costringendomi a riscrivere tutto di nuovo.

    Originariamente inviato da Brendon77
    In questo modo, non solo viene avvertito l'utente che un errore è stato generato (in questo caso la chiave primaria duplicata), ma evita di scrivere nel ClientDataset il nuovo record che sarebbe inesatto siccome avrebbe una chiave primaria già utlizzata.
    Questo è ciò che già avviene quando la ApplyUpdates fallisce: non è necessario, anzi è errato, invocare RevertRecord.

    Originariamente inviato da Brendon77
    Le prove che ho fatto, forse le ho scritte in modo confusionale, sono dettate dal fatto che, dopo averci sbattuto la testa e non riuscendo a capire, mi sono reso conto che l'errore me lo dava Firebird Embedded ma non ne ero sicuro così ho chiesto aiuto (è la prima volta che utilizzo Firebird in generale).
    Meglio procedere "per gradi", studiando il funzionamento del database layer e delle sue peculiarità, per approfondire poi il funzionamento dei componenti per l'accesso ai dati e infine mettere assieme le cose. Usando tutto e subito in questo modo, a fronte di problemi, non si sa a chi dare la colpa, anche perché non sono ben chiari meccanismi che riguardano tutte le parti in gioco.

    Originariamente inviato da Brendon77
    Per la mia applicazione ho utilizzato la versione "non embedded". Tutte le applicazioni Delphi sono naturalmente compilate, ma come avevo detto, ho copiato tutte le librerie e il file EXE in una cartella esterna per verificare il funzionamento della versione embedded su un altro PC... lo scopo era proprio questo
    Anche l'applicazione che esegui da Delphi è compilata: è sempre un eseguibile che viene prodotto e lanciato.

    Originariamente inviato da Brendon77
    Far funzionare l'applicazione su un computer su cui non era installato Firebrid e capire come funzionava la versione Embedded.
    Meglio risolvere i problemi esistenti prima di passare ad un'altra versione del database server.


    Originariamente inviato da Brendon77
    Dalla documentazione di Firebird ho letto che dovevo rinominare la libreria
    "fbembed.dll" in ""gds32.dll"
    Non è necessario, anzi io in genere non lo faccio: modifico la proprietà VendorLib del componente TSQLConnection nel modo opportuno, altrimenti non si ha mai la certezza di quale libreria client di database si sta utilizzando.

    Originariamente inviato da Brendon77
    Tutto andò bene, su un altro pc(senza server firebird) il programma funziona correttamente tranne per un cosa.....
    nell'inserimento di una chiave primaria già utilizzata non compare il mio mesasggio di errore personale e in più viene inserito il record corrispondente (sempre in memoria.... nel database non ci sono modifiche).
    Credo che venga attribuito al cambio di database la causa di errori che sono invece imputabili all'applicazione e che non sono stati riscontrati nel primo caso per... puro caso.

    Originariamente inviato da Brendon77
    Praticamente il comportamento da me progettato e sperato (l'invio del mio messaggio di errore e non inserimento del record me lo da se utilizzo il server Firebird)... se provo ad utilizzare la versione embedded ecco che tutto non funziona....
    Per me non è questo il problema.

    Originariamente inviato da Brendon77
    Penso di essere stato + chiaro e preciso....
    Direi di sì.

    Originariamente inviato da Brendon77
    Immagino che sia inutile fermare il server firebird se in una cartella c'è già la libreira del Firebird Embedded, penso che venga vista prima lei, ma volevo essere sicuro per avere la certezza....
    Usa la proprietà VendorLib, ed eviti questo passaggio.

    Ciao!
    MARCO BREVEGLIERI
    Software and Web Developer, Teacher and Consultant

    Home | Blog | Delphi Podcast | Twitch | Altro...

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.