Visualizzazione dei risultati da 1 a 7 su 7
  1. #1
    Utente di HTML.it
    Registrato dal
    Sep 2005
    Messaggi
    247

    [DELPHI] Problema query database

    Salve, sono un neofita della programmazione in Delphi e ho un piccolo problema con le query ai database MSAccess. Speravo che qualcuno più esperto di me mi aiutasse a risolverlo.

    Vi spiego in breve di cosa si tratta.

    C'è una form principale dove vengono listati, in un ComboBox, tutti i valori di un campo appartenenti a una certa tabella di un database MSAccess.

    E poi c'è una form secondaria (che viene mostrato con il metodo ShowModal) che serve ad aggiungere un record alla suddetta tabella.

    Quando la form secondaria viene chiusa, con un'apposita funzione la form principale "si aggiorna" riottenendo dal database la lista dei valori e reinserendola nel ComboBox.

    Ora il problema è che nel ComboBox non appare l'ultimo valore inserito mediante la form secondaria, come logicamente dovrebbe accadere. Questo perché la query per inserimento del record non è ancora effettivamente completata, quando la form principale si aggiorna richiamando i dati dal database. Non so se mi spiego...

    L'unico metodo valido che ho trovato è quello di far eseguire al programma una query inutile (o altre operazioni del tipo creare e distruggere oggetti inutili), al fine di guadagnare tempo e rendere effettiva la query di inserimento del record. E chi mi dice che questo funzioni su un computer più lento del mio?

    Esiste un metodo più valido? Del tipo "aspetta che la query sia FINITA prima di continuare?"

  2. #2
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,301
    Il comportamento "asincrono" della tua applicazione mi risulta molto singolare.

    Quali componenti usi per l'accesso ai dati?

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

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

  3. #3
    Utente di HTML.it
    Registrato dal
    Sep 2005
    Messaggi
    247
    Questo è il codice presente nella form principale.

    codice:
    procedure Tprincipale.Refresh(Sender: TObject);
    begin
    
    
        DBConnectionString := 'Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' +
        DbCorrente +
        ';Mode=ReadWrite|Share Deny None;Persist Security In' +
        'fo=False';
    
        if FileExists(DbCorrente) then
    
        begin
    
        try
    
        DefaultConnection := TADOConnection.Create(self);
        DefaultConnection.LoginPrompt := False;
        DefaultConnection.ConnectionString := DBConnectionString;
    
        if (DbAssente = False) and (DbCorrente <> '') then
         begin
          materie.Clear;
          materie.Text := 'Scegli una materia...';
          ADOQueryMaterie := TADOQuery.Create(self);
          ADOQueryMaterie.Connection := DefaultConnection;
          ADOQueryMaterie.SQL.Clear;
          ADOQueryMaterie.SQL.Add('SELECT * FROM materie');
          ADOQueryMaterie.Open;
          while not ADOQueryMaterie.eof do
            begin
              Materie.Items.Add(ADOQueryMaterie.FieldValues['Nome']);
              ADOQueryMaterie.Next;
            end;
          ADOQueryMaterie.Free;
          end;
    
          except
              on e: Exception do
                begin
                  if ErroreMostrato = False then
                      begin
                        ErroreMostrato := True;
                        reg.WriteBool('ErroreMostrato',True);
                        raise Exception.Create('Si è verificato un errore nell''accedere al registro "'+
                        DbCorrente+'"'+#13+#10+'Il registro in questione potrebbe essere '+
                        'stato danneggiato. Si consiglia di creare un registro nuovo.'+#13+#10+#13+#10+
                        'L''errore è il seguente: '+#13+#10+e.Message);
                      end;
                end;
           end;
    
    end;
    
    procedure Tprincipale.nuovamateriaClick(Sender: TObject);
    begin
        AggiungiMateria.Position := poMainFormCenter;
        AggiungiMateria.ShowModal;
        if AggiungiMateria.ModalResult = mrOK then Refresh(self); (* UNA VOLTA CHE IL FORM SEDCONDARIO
    "AggiungiMateria" E' STATO CHIUSO CLICCANDO SU "OK",
    AGGIORNA QUESTO FORM MEDIANTE LA FUNZIONE REFRESH *)
    end;
    E quest'altro è il codice presente nella form secondaria.

    codice:
    procedure TAggiungiMateria.okClick(Sender: TObject);
    var NomeMateria : string;
    var ID : string;
    var Comando : string;
    begin
        Comando :=
          'INSERT INTO materie (ID, Nome, VotoUnico) VALUES' +
          ' ( ' +
          ' "' + ID + '", ' +
          ' "' + materia.Text + '", ' +
          ' "0"' +
          ' ) ';
    
      if [CONDIZIONE] then
       begin
        ADOCommand := TADOCommand.Create(self);
        ADOCommand.Connection := DefaultConnection;
        ADOCommand.CommandText := Comando;
        ADOCommand.Execute;
        ADOCommand.Free;
       end
      else [ECC...]
    
    end;

  4. #4
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,301
    Ho preso un po' di tempo per analizzare velocemente il tuo codice.

    Ci sono molte imperfezioni e utilizzi poco ortodossi delle proprietà e dei metodi dei componenti.

    Ad esempio, nel richiamare il metodo Free si dovrebbe usare un costrutto try...finally per garantire che tale metodo venga eseguito anche al verificarsi di un'eccezione.

    Il metodo ShowModal che visualizza una form "modale" restituisce già il valore che nel codice ottieni da ModalResult, quindi non hai bisogno di ispezionare quest'ultima proprietà per capire in quale modo è stato chiuso il form stesso.

    Mi sembra anche molto dispendioso aprire e chiudere l'intera connessione ai dati per eseguire una semplice query e rinfrescare il contenuto di una ComboBox: basterebbe condividere con un DataModule il componente TADOConnection, aprire la connessione all'avvio del programma e riutilizzarla all'interno di componenti per l'accesso ai dati e l'esecuzione di query, magari evitando di crearli a runtime (quando non è necessario, come credo avvenga in questo caso) e facendo uso di parametri qualora le query debbano variare in base ad uno o più valori inseriti all'interno di una condizione (non sembra essere presente questa condizione, al momento, ma è ipotizzabile che succederà).

    Infine, rileggendo attentamente il tuo messaggio, dici di non ottenere l'ultimo record inserito (e questo è il problema centrale) ipotizzando però che ciò sia dovuto ad una "latenza" nell'esecuzione della query che, secondo me, potrebbe non essere la vera causa del problema.

    Analizzando il codice, immagino che non è stato riportato interamente (e non avrebbe senso), quindi fatico a comprendere realmente la fonte dei guai, ma ti esorto a fare un po' di "refactoring" e a semplificare il modo in cui lo hai steso, magari appoggiando componenti sul form invece di crearli a runtime ed evitando anche di aprire e chiudere connessioni, definendole a designtime.

    Insomma, cerca di organizzare meglio il codice e, probabilmente, l'errore salterà agli occhi in modo quasi automatico.

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

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

  5. #5
    Utente di HTML.it
    Registrato dal
    Sep 2005
    Messaggi
    247
    Ti ringrazio moltissimo! Le modifiche che mi hai consigliato non solo hanno risolto il problema, ma hanno anche reso il programma sensibilmente più veloce.

    Ora tengo una sola connessione aperta e va tutto bene.

    Comunque non posso creare i componenti in design-time, perché il fatto che vengano creati o meno è subordinato ad alcune condizioni. Inoltre, a seconda delle circostanze, il programma deve connettersi a database diversi. Perciò devo farlo per forza in runtime.


    E' difficile trovare persone gentili che siano disposte ad analizzare decine di stringhe di codice scritte a cavolo di cane!

    Grazie ancora,
    ciao

  6. #6
    Moderatore di Programmazione L'avatar di alka
    Registrato dal
    Oct 2001
    residenza
    Reggio Emilia
    Messaggi
    24,301
    Originariamente inviato da firefox88
    Ti ringrazio moltissimo! Le modifiche che mi hai consigliato non solo hanno risolto il problema, ma hanno anche reso il programma sensibilmente più veloce.
    Ne sono felice.

    Originariamente inviato da firefox88
    Comunque non posso creare i componenti in design-time, perché il fatto che vengano creati o meno è subordinato ad alcune condizioni. Inoltre, a seconda delle circostanze, il programma deve connettersi a database diversi. Perciò devo farlo per forza in runtime.
    La condizione di potersi collegare a database diversi a runtime non implica che tu debba creare a runtime anche i componenti; ad esempio, puoi definire i componenti necessari a designtime (come un ADOConnection) e impostarne unicamente i parametri per la connessione a runtime.

    Ovvio, se oltre a database diversi esiste anche la necessità di collegarsi a tali database con librerie e piattaforme diverse, allora concordo con te che crearle a runtime è senz'altro la scelta obbligata; tuttavia, se fai solo uso di ADO, puoi tranquillamente appoggiare i componenti e definire a runtime le proprietà, senza accollarti l'onere di crearli, riducendo la quantità di codice da gestire.

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

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

  7. #7
    Utente di HTML.it
    Registrato dal
    Sep 2005
    Messaggi
    247
    Grazie dei consigli, a presto.

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 © 2024 vBulletin Solutions, Inc. All rights reserved.