Delphi

Sganciare la UI dal dataset: dai risultati di una query a un array filtrabile

calendar_today personTeam EGSOFT schedule4 min di lettura
info

Disclaimer: le informazioni pubblicate in questa sezione hanno finalità di pura divulgazione tecnica. EG Software S.r.l. non si assume alcuna responsabilità per un utilizzo improprio dei contenuti, né per eventuali danni diretti o indiretti derivanti dalla loro applicazione, e non garantisce l'aggiornamento, l'accuratezza o la completezza delle informazioni riportate. Prima di utilizzare in produzione codice o procedure qui descritte, verificane sempre l'adeguatezza al proprio contesto.

Tenere aperta una connessione al database per tutto il tempo in cui l'utente lavora su un elenco non è sempre desiderabile: consuma una risorsa condivisa, e se la sessione cade si perde anche la possibilità di mostrare i dati già caricati. Una tecnica semplice consiste nell'eseguire la query una sola volta, copiare i risultati in un array di record e da quel momento lavorare solo in memoria, filtrando lato client senza più toccare il database.

Dalla query a un array di record

Rispetto a un semplice array di stringhe, un array di record tipizzati conserva tutti i campi che servono, non solo quello mostrato in un controllo visuale.

type
  TRigaAnagrafica = record
    ID: Integer;
    Nome: string;
  end;

  TQueryResultRecordArray = class
  private
    FQuery: TADOQuery;
    FRecordArray: TArray;
  public
    constructor Create(AConnection: TADOConnection);
    destructor Destroy; override;
    function ExecuteQuery(const SQL: string): Boolean;
    function Filter(const Testo: string): TArray;
  end;

constructor TQueryResultRecordArray.Create(AConnection: TADOConnection);
begin
  FQuery := TADOQuery.Create(nil);
  FQuery.Connection := AConnection;
end;

destructor TQueryResultRecordArray.Destroy;
begin
  FQuery.Free;
  inherited;
end;

function TQueryResultRecordArray.ExecuteQuery(const SQL: string): Boolean;
var
  Riga: TRigaAnagrafica;
begin
  Result := False;
  SetLength(FRecordArray, 0);
  FQuery.Close;
  FQuery.SQL.Text := SQL;
  try
    FQuery.Open;
    while not FQuery.Eof do
    begin
      Riga.ID := FQuery.FieldByName('ID').AsInteger;
      Riga.Nome := FQuery.FieldByName('Nome').AsString;
      FRecordArray := FRecordArray + [Riga];
      FQuery.Next;
    end;
    Result := True;
  finally
    FQuery.Close; // i dati ormai vivono nell'array, la connessione non serve più
  end;
end;

Filtrare senza nuove query

Con i dati già in memoria, un filtro testuale diventa un semplice ciclo, senza dover riformulare l'SQL né riaprire la connessione:

function TQueryResultRecordArray.Filter(const Testo: string): TArray;
var
  Riga: TRigaAnagrafica;
begin
  SetLength(Result, 0);
  for Riga in FRecordArray do
    if ContainsText(Riga.Nome, Testo) then
      Result := Result + [Riga];
end;

Quando conviene, quando no

Questo approccio ha senso per elenchi di dimensione ragionevole (liste di anagrafiche, categorie, configurazioni) che l'utente consulta e filtra ripetutamente in una singola sessione operativa. Per dataset molto grandi o che cambiano di continuo, filtrare lato server resta la scelta più corretta: l'array in memoria è un compromesso, non una regola universale. La chiusura esplicita della connessione (FQuery.Close) subito dopo la copia dei dati è il dettaglio che rende evidente l'intenzione: da qui in poi si lavora solo sui dati locali.

Altri articoli su Delphi grid_viewTutte le tematiche
Scrivici su WhatsApp