* * * *

Privacy Policy

Blog italiano

Clicca qui se vuoi andare al blog italiano su Lazarus e il pascal.

Forum ufficiale

Se non siete riusciti a reperire l'informazione che cercavate nei nostri articoli o sul nostro forum vi consiglio di visitare il
Forum ufficiale di Lazarus in lingua inglese.

Lazarus 1.0

Trascinare un file nel programma
DB concetti fondamentali e ZeosLib
Recuperare codice HTML da pagina web
Mandare mail con Lazarus
Stabilire il sistema operativo
Esempio lista in pascal
File INI
Codice di attivazione
Realizzare programmi multilingua
Lavorare con le directory
Utilizzare Unità esterne
TTreeView
TTreeview e Menu
Generare controlli RUN-TIME
LazReport, PDF ed immagini
Intercettare tasti premuti
Ampliare Lazarus
Lazarus e la crittografia
System Tray con Lazarus
UIB: Unified Interbase
Il file: questo sconosciuto
Conferma di chiusura di un applicazione
Liste e puntatori
Overload di funzioni
Funzioni a parametri variabili
Proprietà
Conversione numerica
TImage su Form e Panel
Indy gestiore server FTP lato Client
PopUpMenu sotto Pulsante (TSpeedButton)
Direttiva $macro
Toolbar
Evidenziare voci TreeView
Visualizzare un file Html esterno
StatusBar - aggirare l'errore variabile duplicata
Da DataSource a Excel
Le permutazioni
Brute force
Indy 10 - Invio email con allegati
La gestione degli errori in Lazarus
Pascal Script
Linux + Zeos + Firebird
Dataset virtuale
Overload di operatori
Lavorare con file in formato JSON con Lazarus
Zeos ... dietro le quinte (prima parte)
Disporre le finestre in un blocco unico (come Delphi)
Aspetto retrò (Cmd Line)
Lazarus 1.0
Come interfacciare periferica twain
Ubuntu - aggiornare free pascal e lazarus
fpcup: installazioni parallele di lazarus e fpc
Free Pascal e Lazarus sul Raspberry Pi
Cifratura: breve guida all'uso dell'algoritmo BlowFish con lazarus e free pascal.
Creare un server multithread
guida all'installazione di fpc trunk da subversion in linux gentoo
Indice
DB concetti fondamentali e connessioni standard
Advanced Record Syntax
DB concetti fondamentali e DBGrid
DB concetti fondamentali e TDBEdit, TDBMemo e TDBText
Advanced Record Syntax: un esempio pratico
Superclasse form base per programmi gestionali (e non)
Superclasse form base per programmi gestionali (e non) #2 - log, exception call stack, application toolbox
Superclasse form base per programmi gestionali (e non) #3 - traduzione delle form
Superclasse form base per programmi gestionali (e non) #4 - wait animation
Un dialog per la connessione al database:TfmSimpleDbConnectionDialog
Installare lazarus su mac osx sierra
immagine docker per lavorare con lazarus e free pascal
TDD o Test-Driven Development
Benvenuto! Effettua l'accesso oppure registrati.
Aprile 19, 2024, 07:16:23 pm

Inserisci il nome utente, la password e la durata della sessione.

379 Visitatori, 0 Utenti

Autore Topic: mie utility su database  (Letto 4530 volte)

petrusic

  • Hero Member
  • *****
  • Post: 589
  • Karma: +0/-0
mie utility su database
« il: Agosto 25, 2022, 06:33:34 pm »
Nel costruire il mio file di utility per accedere al database coi miei dati (SQLite3), ho inserito nel mio primo programma alcune funzioni  come
Codice: [Seleziona]
 function OpenDbQuery1F1(sql: String): Boolean;
 function OpenDbQuery2F1(sql: String): Boolean; 
Ciò, perchè mentre è ancora attiva la Query1F1, mi è successo di dovere eseguire una Query2F1. Bene

Sto ora scrivendo un altro programma che accede sempre allo stesso database, ma  soltanto attraverso la Query1F1, quindi non ha bisogno di un secondo oggetto Query.

Ebbene, la compilazione di quest'ultimo programma mi restituisce un mesaaggio d'errore perchè non trova la Query2F1.

Francamente non me l'aspettavo. Non capisco perchè, se il file di utility contiene due function  di tipo Query, ma al programma corrente occorre richiamarne una sola, il compilatore debba protestare.

Io non so come fate voi di fronte ad una situazione del genere.

Io attualmente vedo solo una via: non utilizzare file utility, ma scrivere le function direttamente dentro ciascun programma.
Mi sembra una scelta bambinesca, ma non saprei fare diversamente.

Per completezza riporto le immagini dei form dei due diversi programmi.
ciao ciao

DragoRosso

  • Scrittore
  • Hero Member
  • *****
  • Post: 1266
  • Karma: +43/-0
  • Prima ascoltare, poi decidere
Re:mie utility su database
« Risposta #1 il: Agosto 25, 2022, 07:09:35 pm »
Non hai importato nella Uses il corretto file delle definizioni.

Inoltre hai definito anonime le funzioni sotto elencate.

Se le vuoi anonime ma di uso globale, devi definirle nel "global section" (cioè nella sezione INTERFACE)

Ciao
« Ultima modifica: Agosto 25, 2022, 07:13:30 pm da DragoRosso »
:) Ogni alba è un regalo, ogni tramonto è una conquista :)

petrusic

  • Hero Member
  • *****
  • Post: 589
  • Karma: +0/-0
Re:mie utility su database
« Risposta #2 il: Agosto 25, 2022, 10:08:22 pm »
Non hai importato nella Uses il corretto file delle definizioni.

Inoltre hai definito anonime le funzioni sotto elencate.
Riporto qui le uses dei due programmi, perchè non ho capito dove avrei sbagliato.

1-Progetto "DomusRatioCancResta"
Codice: [Seleziona]
unit frm1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, DB, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ZConnection, ZDataset,
  utilmie, utilmiedb;

type

  { TForm1 }

  TForm1 = class(TForm)
    BPulsAvanti: TButton;
    Button2: TButton;
    DataSource1: TDataSource;
    Label1: TLabel;
    LBggContab: TListBox;
    ZConnection: TZConnection;
    ZQuery1: TZQuery;
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure LBggContabEnter(Sender: TObject);
  private

  public

  end;

var
  Form1: TForm1;

  dbCopia, dbCorr, dbOrig, dbProve, percorso: String;

implementation

{$R *.lfm}

{ TForm1 }
var
  totRec: Integer;

//  dataOggi,   dbCopia, dbCorr, dbOrig, dbProve, percorso, sql, status ,striMia: String;
  dataOggi, sql, status ,striMia: String;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Form1.Caption:= 'CANCELLAZIONE, in Tb.restacassagg di tutti i record di una giornata contabile';
  percorso := ExtractfilePath(Application.ExeName);
//------------------------------------ Assegno percorso per l'accesso al DB corretto
  dbCopia:= '/media/dirdati/dativari/contabfam/ContabFamdb(copia)';         // )
  dbOrig:= '/media/dirdati/dativari/contabfam/ContabFamdb';                 // ( per impostare dbCorr:= dbOrig o dbProve -> Form1.Panel1Enter
  dbProve:= '/media/dirdati/dativari/contabfam/ContabFamdb_prove';          // )
//------------------------------------------------------------------------------------
end;                                           

2-Progetto DomusRatio (Di questo riporto soltanto la parte iniziale della unit frm1
Codice: [Seleziona]
unit FrmMain;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, DB, Forms, Controls, Graphics, Dialogs, Menus, ExtCtrls,
  FileUtil, StdCtrls, ZConnection, ZDataset, Frm5, Frm6, Frm7,
  utilmie, utilmiedb;
//  FileUtil, process, StdCtrls, ZConnection, ZDataset, Frm5, Frm6, Frm7,



type

    { TForm1 }

    TForm1 = class(TForm)
    DataSource1: TDataSource;
    DataSource2: TDataSource;
    Image1: TImage;
    LAttesa: TLabel;
    MainMenu1: TMainMenu;
    Menu1: TMenuItem;
    Menu11: TMenuItem;
    Menu2: TMenuItem;
    Menu21: TMenuItem;
    Menu22: TMenuItem;
    Menu221: TMenuItem;
    Menu222: TMenuItem;
    Menu2221: TMenuItem;
    Menu2222: TMenuItem;
    Menu2223: TMenuItem;
    Menu2224: TMenuItem;
    Menu2225: TMenuItem;
    Menu223: TMenuItem;
    Menu224: TMenuItem;
    Panel1: TPanel;
    ZConnection: TZConnection;
    ZReadOnlyQuery1: TZReadOnlyQuery;
    ZReadOnlyQuery2: TZReadOnlyQuery;
    procedure FormCreate(Sender: TObject);
    procedure Menu11Click(Sender: TObject);
    procedure Menu21Click(Sender: TObject);     // Inserimento Movimenti giornalieri
    procedure Menu221Click(Sender: TObject);    // Ricerca Movimenti per Descrizione (tipoRicerca:= '0')
    procedure Menu2221Click(Sender: TObject);   // Ricerca Movimenti per Voce principale di Cassa (tipoRicerca:= '1')
    procedure Menu2222Click(Sender: TObject);   // Ricerca Movimenti per Voce di Sottoconto di Cassa (tipoRicerca:= '2')
    procedure Menu2223Click(Sender: TObject);   // Ricerca Movimenti per Voce Primaria di Collegamento (tipoRicerca:= '3')
    procedure Menu2224Click(Sender: TObject);   // Ricerca Movimenti per Voce Secondaria di Collegamento (tipoRicerca:= '4')
    procedure Menu2225Click(Sender: TObject);   // Ricerca Movimenti per Voce di Sottoconto di Collegamento (tipoRicerca:= '5')
    procedure Menu223Click(Sender: TObject);    // Ricerca per Componente familiare (tipoRicerca:= '6')
    procedure Menu224Click(Sender: TObject);    // Ricerca per Importo (tipoRicerca:= '7')
    procedure Panel1Enter(Sender: TObject);
end;

const
  maskLire: String = '#,###,##0';
  maskEuro: String = '#,###,##0.#0';

var
  Form1: TForm1;


  dbCopia: String;
  dbOrig: String;
  dbProve: String;
  dbCorr: String;
  dataCont, dataSys, nomeGiorno, nomeMese, percorso: String;
  ggApertaChiusa: String;      //  (campo vuoto) = Giornata contabile NUOVA,   "C" = Giornata contabile CHIUSA,   "A" = Giornata contabile APERTA
  tipoValuta: String;


implementation
{$R *.lfm}

{ TForm1 }

procedure TForm1.Menu11Click(Sender: TObject);   // Scelta Menu' "File + Esci"
begin
  Application.Terminate;
end;                                     

I file delle mie utility sono dentro un'unica directory:
Codice: [Seleziona]
$ ls /media/dirdati/dativari/lazarus_progetti/lazarus_progetti_miei/util_mie
backup  daticomuni.pas  lib  utilmiedb.pas  utilmie.pas
riporto parte del contenuto del file "utilmiedb.pas"
Codice: [Seleziona]
unit utilmiedb;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Dialogs,
//  DB, Forms, Controls, Graphics, Menus, ExtCtrls,
  DB, Forms, Controls, Menus, ExtCtrls,
  FileUtil, StdCtrls,
  ZConnection, ZDataset;


type
  TstrOut = Integer;

 function DbContaRecInOpen(sql: String): Integer;    // Esegue la OPen del DB tramit Query contenuta in "sql" ed accerta la presenza di record di riscontro
 function EstraiVocePianCont(sql: String): String;    // Estrae dalla Tabella "piancont" la Voce contabile, a cui accoda il contenuto del campo "ContrPartSiNo"
 function EstraiCoVoColleg(sql, segnal: String): String;    // Estrae dalla Tabella "racodvoci" il codice di sottoconto contrappoto al tipo inmdicato in "segnal"
 function OpenDbQuery1F1(sql: String): Boolean;
 function OpenDbQuery2F1(sql: String): Boolean;

implementation
uses
  frm1;
function OpenDbQuery1F1(sql: String): Boolean;     // funzione usata per accedere alla lettura di un solo Record della TB.piancont o dalla TB.racodvoci
var
  swOpenErro: Boolean = False;
begin
//----------- Open del DB ------------------------------------------------------
  Form1.ZConnection.Database := dbCorr;
  Form1.ZQuery1.SQL.Text := sql;
  try
    Form1.ZQuery1.Open;
    except
    on E: Exception do
    begin
      WriteLn('ERRORE nella OPEN del ContabFamdb (sql: "' + sql + '" ' + IntToStr(E.HelpContext) + ': ' + E.Message);
      swOpenErro:= True;
    end;
  end;
  Result:= swOpenErro;
end;
function OpenDbQuery2F1(sql: String): Boolean;     // funzione usata per accedere alla lettura di un solo Record della TB.piancont o dalla TB.racodvoci
var
  swOpenErro: Boolean = False;
begin
//----------- Open del DB ------------------------------------------------------
  Form1.ZConnection.Database := dbCorr;
  Form1.ZReadOnlyQuery2.SQL.Text := sql;
  try
    Form1.ZReadOnlyQuery2.Open;
    except
    on E: Exception do
    begin
      WriteLn('ERRORE nella OPEN del ContabFamdb (sql: "' + sql + '" ' + IntToStr(E.HelpContext) + ': ' + E.Message);
      swOpenErro:= True;
    end;
  end;
  Result:= swOpenErro;
end;                                                       

Spero che possa bastare per aiutarmi a capire come dovrei intervenire.
ciao ciao

DragoRosso

  • Scrittore
  • Hero Member
  • *****
  • Post: 1266
  • Karma: +43/-0
  • Prima ascoltare, poi decidere
Re:mie utility su database
« Risposta #3 il: Agosto 25, 2022, 10:40:22 pm »
Le dichiarazioni dovrebbero essere a posto. Non posti però la parte di codice dove usi la funzione (con le Uses).

Se nel codice dove usi la funzione non genera errore e genera solo l'errore per la "mancanza" dell'altra che però non usi, allora è un bel dilemma.

Io non saprei come aiutarti.

:) Ogni alba è un regalo, ogni tramonto è una conquista :)

petrusic

  • Hero Member
  • *****
  • Post: 589
  • Karma: +0/-0
Re:mie utility su database
« Risposta #4 il: Agosto 26, 2022, 11:40:02 am »
Le dichiarazioni dovrebbero essere a posto. Non posti però la parte di codice dove usi la funzione (con le Uses).
Se nel codice dove usi la funzione non genera errore e genera solo l'errore per la "mancanza" dell'altra che però non usi, allora è un bel dilemma.
Cerco di riportare il codice con ordine
Il programma richiamala la  funzione "DbContaRecInOpen" , presente nella unit "utilmiedb" delle utility mie:
Codice: [Seleziona]
unit frm1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, DB, Forms, Controls, Graphics, Dialogs, StdCtrls,
  FileUtil, ZConnection, ZDataset,
  utilmie, utilmiedb;

type

  { TForm1 }

  TForm1 = class(TForm)
    BPulsAvanti: TButton;
    Button2: TButton;
    DataSource1: TDataSource;
    Label1: TLabel;
    LBggContab: TListBox;
    ZConnection: TZConnection;
    ZQuery1: TZQuery;
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure LBggContabEnter(Sender: TObject);
  private

  public

  end;       
. . .
procedure TForm1.LBggContabEnter(Sender: TObject);
var
  dtGGfa: String;
begin
 BPulsAvanti.Caption:='Seleziona data per Cancellazione Record e' + LineEnding + Space(30) + 'CLICCA QUI';
 dataOggi:= CarDtCalendario();
 dtGGfa:= CalcDataGGfa(30);
  dbCorr:= dbProve;
  CopyFile(dbOrig, dbCorr);
  ShowMessage('----- DomusRatioCancResta -----' + System.lineending + 'DB Origine: ' + dbOrig + System.lineending + 'copiato in ' + System.lineending + 'DB di prova: ' + dbProve);
 //----------- Open del DB ------------------------------------------------------
  ZConnection.Database:= dbCorr;
  sql:= 'SELECT DtCoMovg, StaDtMovg FROM riepmovg WHERE DtCoMovg <= ' + dataOggi + ' AND DtCoMovg >= ' + dtGGfa + ' ORDER BY DtCoMovg DESC';
  totRec:= DbContaRecInOpen(sql);                                         

l'unit utilmiedb contiene la function DbContaRecInOpen:
Codice: [Seleziona]
unit utilmiedb;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Dialogs,
//  DB, Forms, Controls, Graphics, Menus, ExtCtrls,
  DB, Forms, Controls, Menus, ExtCtrls,
  FileUtil, StdCtrls,
  ZConnection, ZDataset;


type
  TstrOut = Integer;

 function DbContaRecInOpen(sql: String): Integer;    // Esegue la OPen del DB tramit Query contenuta in "sql" ed accerta la presenza di record di riscontro
 function EstraiVocePianCont(sql: String): String;    // Estrae dalla Tabella "piancont" la Voce contabile, a cui accoda il contenuto del campo "ContrPartSiNo"
 function EstraiCoVoColleg(sql, segnal: String): String;    // Estrae dalla Tabella "racodvoci" il codice di sottoconto contrappoto al tipo inmdicato in "segnal"
 function OpenDbQuery1F1(sql: String): Boolean;
 function OpenDbQuery2F1(sql: String): Boolean;

implementation
uses
  frm1;                                           


function DbContaRecInOpen(sql: String): Integer;    // Esegue la OPen del DB tramite Query contenuta in "sql" ed accerta la presenza di record di riscontro
var
  totRec: Integer;

begin
  Form1.ZConnection.Database:= dbCorr;
  Form1.ZQuery1.SQL.Text:= sql;
  try
    Form1.ZQuery1.Open;
    except
    on E: Exception do
      WriteLn('ERRORE nella OPEN-sql= "' + sql + ' -"' + IntToStr(E.HelpContext) + ': ' + E.Message + '"-');
  end;
  totRec:= Form1.ZQuery1.RecordCount;
  Result:= totRec;
  Form1.ZQuery1.Close;
end;                           
che è quella che viene richiamata.


Tuttavia nella unit sono presenti anche altre function, non richiamate nel programma corrente.
Ebbene il compilatore fornisce il seguente errore per ben 9 volte puntando a tutte le righe tipicamente anomale delle altre function, pur non essendo mai richiamate:
Citazione
Compila il progetto, Destinazione: DomusRatioCancResta: Codice di uscita 1, Errori: 9
utilmiedb.pas(54,9) Error: identifier idents no member "ZReadOnlyQuery2"
. . .
utilmiedb.pas(138,9) Error: identifier idents no member "ZReadOnlyQuery2"

Io vedo solo 2 alternative:
- creare una unit di utilility per ciascuna function:
- abbandonare il concetto unit di utility e riportare le function di volta in volta che servono, dentro il programma chiamante.
« Ultima modifica: Agosto 26, 2022, 11:42:05 am da petrusic »
ciao ciao

DragoRosso

  • Scrittore
  • Hero Member
  • *****
  • Post: 1266
  • Karma: +43/-0
  • Prima ascoltare, poi decidere
Re:mie utility su database
« Risposta #5 il: Agosto 26, 2022, 01:51:35 pm »
Intanto devi riportare correttamente quello che accade: ciò che hai riportato adesso è ben diverso da quello di inizio topic, perchè altrimenti non riusciamo ad aiutarti.

Innanzitutto, la compilazione di una unità viene comunque eseguita, anche se l'unità stessa viene usata solo in parte.

In questo caso il compilatore di dice che la classe ZReadOnlyQuery2 "ha qualcosa che non và", questo indipendentemente dal fatto che venga usata o meno.

Se l'uso di quella classe non è corretto, ovviamente anche le funzioni / procedure / metodi che la usano non vengono compilati.

Non sò come e soprattutto dove viene dichiarata quella classe, ma è probabile che sia li il problema: qualche tua unità in uso chiama la FORM1 ?

Due cose però devo dirti sulla programmazione:

1) Quando crei una nuova unità, cerca per quanto possibile di non usare classi dichiarate "sotto" una FORM di un'altra unità. E' buona pratica non mantenere dipendenza da oggetti visuali dichiarate in altre unità, eccetto per chiamare metodi come costruttori, distruttori o Show e ShowModal.

2) Quando crei un unità con dipendenze, devi assolutamente verificare che tutte le dipendenze siano "istanziate", non basta solo includere una unita nelle USES perchè all'interno di quella unità qualcosa magari non verrà istanziato automaticamente.

Terza cosa, ancora come consiglio, le Query potresti istanziarle a runtime e definirle direttamente nella tua unità dove le usi senza usare il DRAG & DROP in una Form.

Ciao
:) Ogni alba è un regalo, ogni tramonto è una conquista :)

DragoRosso

  • Scrittore
  • Hero Member
  • *****
  • Post: 1266
  • Karma: +43/-0
  • Prima ascoltare, poi decidere
Re:mie utility su database
« Risposta #6 il: Agosto 26, 2022, 02:55:11 pm »
Io vedo solo 2 alternative:
- creare una unit di utilility per ciascuna function:
- abbandonare il concetto unit di utility e riportare le function di volta in volta che servono, dentro il programma chiamante.

No, non funziona così. Il concetto di Unit è fondamentale nel Pascal e ha un senso ben preciso.

Nella programmazione ad oggetti il tutto si basa appunto sugli "oggetti" e ci sono alcune regole da seguire. Se si vuole programmare come nel vecchio "C" ci si scontra con delle difficoltà logiche.

In una Unit normalmente si raccolgono tutte le funzionalità logiche legate ad una specifica esigenza: se nella tua unit vuoi inserire delle funzioni che svolgano delle attività su un database, forse dovresti creare una classe di "utility" dove inserirai tutte le funzionalità che ti servono.
Tieni presente, visto che usi SQLite, che non puoi effettuare chiamate contemporanee (ad esempio da più Thread) al Database, tanto vale che definisci tutte le funzionalità che ti servono in quella Unit. Quindi "oggetti", "connessione", "query", etc ... al database saranno definiti li.

Ora viene il bello: il tutto sarebbe semplice se fosse fatto a runtime senza uso del "Drag & DROP" in una Form. Perchè se no torniamo punto a capo, creo un Form ci butto tutto dentro ... ma dipendo da un Form.
Lazarus (e non solo) però a pensato anche a questo e ha progettato una UNIT che serve proprio a questo scopo: si chiama "Modulo Dati" e deriva dalla classe TDataModule.

E' visuale e ci puoi mettere dentro i componenti del tuo DATABASE, ma è visuale SOLO a "design time" e serve appunto a facilitare la vita ai programmatori che possono usare il "Drag & Drop" per i componenti di gestione di un database ma non su una FORM. Non vanno inseriti i componenti visuali come "DBGRID" perchè come accennavo il TDataModule non è visuale a runtime.

Già questo potrebbe essere un buon punto di inizio per lavorarci.

Ahh, dimenticavo il "Modulo Dati" si crea andando nel menu "File", "Nuovo ..." e poi scegliendo "MODULO DATI".


EDIT: nel costruttore e nel distruttore del TDamodule puoi ad esempio creare la tua connessione al database e distruggerla alla fine del programma.

Ciao
« Ultima modifica: Agosto 26, 2022, 02:58:28 pm da DragoRosso »
:) Ogni alba è un regalo, ogni tramonto è una conquista :)

petrusic

  • Hero Member
  • *****
  • Post: 589
  • Karma: +0/-0
Re:mie utility su database
« Risposta #7 il: Agosto 26, 2022, 03:05:48 pm »
1) Quando crei una nuova unità, cerca per quanto possibile di non usare classi dichiarate "sotto" una FORM di un'altra unità. E' buona pratica non mantenere dipendenza da oggetti visuali dichiarate in altre unità, eccetto per chiamare metodi come costruttori, distruttori o Show e ShowModal.
Sono d'accordo, ma non saprei come regolarmi per accedere a tabelle di database. Ecco perchè ho utilizzato quel metodo.

Citazione da: DragoRosso
le Query potresti istanziarle a runtime e definirle direttamente nella tua unità dove le usi senza usare il DRAG & DROP in una Form.
Mi potresti fare un esempio pratico? Così non riesco a seguire il ragionamento.

Scusa, ma la terminologia inglese o inglesizzata non fa parte del mio linguaggio tecnico.



ciao ciao

petrusic

  • Hero Member
  • *****
  • Post: 589
  • Karma: +0/-0
Re:mie utility su database
« Risposta #8 il: Agosto 26, 2022, 03:39:51 pm »
Forse ho trovato:
http://www.lazaruspascal.it/index.php?page=111
Penso che è quello a cui ti riferisci quando parli di instanziare query a runtime.

Non mi sembra facile da comprendere, ma cerco di capire ugualmente e provo ad applicarlo praticamente.
« Ultima modifica: Agosto 26, 2022, 04:08:22 pm da petrusic »
ciao ciao

DragoRosso

  • Scrittore
  • Hero Member
  • *****
  • Post: 1266
  • Karma: +43/-0
  • Prima ascoltare, poi decidere
Re:mie utility su database
« Risposta #9 il: Agosto 26, 2022, 04:36:47 pm »
Forse quello è un pò troppo avanzato, usa le interfacce e cursori direttamente, ma se te la senti fai pure.

Ti posto intanto un esempio di runtime come lo pensavo io, forse più accessibile.

P.S.: è stato creato in Windows x64, c'è anche la dll di SQLite3. Adattalo eventualmente se usi Linux (in realtà non dovrebbero esserci modifiche se non nelle proprietà di compilazione).

Ciao
« Ultima modifica: Agosto 26, 2022, 04:39:46 pm da DragoRosso »
:) Ogni alba è un regalo, ogni tramonto è una conquista :)

petrusic

  • Hero Member
  • *****
  • Post: 589
  • Karma: +0/-0
Re:mie utility su database
« Risposta #10 il: Agosto 26, 2022, 07:49:23 pm »
Ti posto intanto un esempio di runtime come lo pensavo io, forse più accessibile.
P.S.: è stato creato in Windows x64, c'è anche la dll di SQLite3. Adattalo eventualmente se usi Linux (in realtà non dovrebbero esserci modifiche se non nelle proprietà di compilazione).

Ti ringrazio per la disponibilità e la pazienza. In effetti io cercavo qualcosa del genere sin da quando ho cominciato a provare l'accesso a database in Lazarus.

Ora che ho preso confidenza con gli strumenti grafici di Zeos, ricominciare praticamente da zero non è semplice, ma sono sicuro che ne vale la pena.

Ho dato una guardata veloce al progettino d'esempio che mi hai gentilmente girato. Ho visto che il programma principale richiama una unity al cui interno ci sono tre utility, di cui la prima è un costruttore, la seconda è un distruttore e l'ultima è la function vera e propria.

Nel costruttore  ho incontrato:
Codice: [Seleziona]
 ZConnection1 := TZConnection.Create(nil);    
. . .
ZTable1 := tZTable.Create(nil);   
Non ho capito se quel (nil) è un'impostazione obbligata o se, invece, può essere sostituita da nomi di tabelle(nella prima create) o da nomi di colonne (nella seconda create), come si potrebbe fare, per esempio in fase di generazione di un nuovo database, con le relative tabelle.

Poi credo che l'utilizzo segua il criterio di Zeoslib, cioè, se esiste una connessione già attiva ed occorre procedere con una seconda query, senza chiudere quella attiva, occorre dare vita ad una ZConnection2 dentro un'ulteriore unit, con un suo costruttore, un suo distruttore e la sua funzione di lettura, scrittura, aggiornamento, . . .  del database.

Spero di avere capito bene.
ciao ciao

DragoRosso

  • Scrittore
  • Hero Member
  • *****
  • Post: 1266
  • Karma: +43/-0
  • Prima ascoltare, poi decidere
Re:mie utility su database
« Risposta #11 il: Agosto 26, 2022, 10:21:47 pm »
Il parametro del costruttore Create generalmente viene usato per consentire l'apparentamento, ossia principalmente chi ha la responsabilità della distruzione del componente.

Nel caso sia nil, qualcuno dovrà chiamare il metodo free del componente.

In questo caso i due componenti che hai indicato vengono messi a FREE dal metodo DESTRUCTOR della classe.

Ora se osservi bene, vedrai che il codice nella parte visuale (unit1) costruisce la classe con il parametro a SELF, questo fà si non sia necessario chiamare il distruttore FREE manualmente in quanto vi provvede automaticamente la FORM1 (self in questo caso indica la FORM1).

Codice: [Seleziona]
MiaUtilita := TMyUtility.Create(self);

Così facendo il metodo DESTRUCTOR dell'istanza "MiaUtilita" verrà chiamato quando la FORM1 si chiude.

Per quello che riguarda la connessione, dentro la classe puoi fare quello che vuoi, inserire 10 ZQuery, 15 ZTable, 5 ZConnection, etc .... (sono numeri a caso chiaramente), e gestire ogni singolo componente o sua proprietà come meglio credi. Sei in una classe e tutti gli "oggetti" della classe appartengono alla classe e li dentro puoi fare ciò che vuoi.

Tra l'altro vedrai che ZConnetcion1 e ZTable1 sono dichiarate "public" e quindi puoi accedervi anche dalla Unit1. In realtà dovrebbero essere dichiarate "private" perchè dovresti accedervi solo con i metodi della classe "TMyUtility".

Codice: [Seleziona]
type
  TMyUtility = Class
  private
      ZConnection1: TZConnection;
      ZTable1: TZTable;
  public
      function LeggiLaPrimaRiga: boolean;
      constructor Create(Owner: TComponent); overload;
      destructor Destroy;                    override;
  end;     

Se vuoi continuare con le componenti grafiche, invece di usare un FORM usa un TDATAMODULE come ti ho indicato in un post precedente.

Magari poi "mixare" intanto le due tecniche finchè non prendi mano.

Ciao
:) Ogni alba è un regalo, ogni tramonto è una conquista :)

petrusic

  • Hero Member
  • *****
  • Post: 589
  • Karma: +0/-0
Re:mie utility su database
« Risposta #12 il: Agosto 27, 2022, 04:20:18 pm »
@ DragoRosso

Mentre ti comunico che, per terminare al più presto il programmino che avevo in corso d'opera, ho preferito mettere un pò da parte la novità che mi hai indicato per l'accesso ai DB,

Stamani ho finito di provarlo. Funziona benissimo.

Ora, però, visto che ho la calma necessaria per riconsiderare e modificare quanto fatto sui DB, mi pare il momento giusto per addentrarmi nella tecnica d'accesso RunTime.

Ho perciò ripreso l'esempio che mi hai postato ed ho cercato di applicarne il metodo nel programma appena finito che è il più semplice fra quelli realizzati.

Ho quindi cominciato a formare una Unit Class dove ho riportato il costruttoire ed il distruttore di una ZConection che, penso,  dovrebbe rendersi disponibile alle varie occorrenze. Andrebbe perciò personalizzata, al momento, nel costruttore.
Riprendo perciò le righe dell'esempio:
Codice: [Seleziona]
 with ZConnection1 do
    begin
      ControlsCodePage := cCP_UTF8;
      AutoEncodeStrings := True;
      ClientCodepage := 'UTF-8';
      Properties.Add('AutoEncodeStrings=True');
      Properties.Add('controls_cp=CP_UTF8');
      Properties.Add('codepage=UTF-8');
      Port := 0;
      Database := '.\db.s3db';          <== qui dovrei mettere il percorso completo del mio DB (dbProve, dbOrig)
      Protocol := 'sqlite-3';
    end;
Dovrei potere impostare la proprietà Database col percorso del DB da manipolare al momento:
- (dbOrig:= '/media/dirdati/dativari/contabfam/ContabFamdb';)
- (dbProve:= '/media/dirdati/dativari/contabfam/ContabFamdb_prove').

Ecco, non ho capito come intervenire, perchè è il programma chiamante che conosce il percorso corretto, Ma come faccio a passargli la stringa? Qui?
Codice: [Seleziona]
MiaUtilita := TMyUtility.Create(self, dbOrig)
   

Lo stesso problema nasce quando, subito dopo dovrei impostare i parametri di identificazione della tabella subordinata del DB:
Codice: [Seleziona]
 ZConnection1.Connected:= True;
  ZTable1 := tZTable.Create(nil);
  with ZTable1 do
    begin
      Connection := ZConnection1;
      SortedFields := 'ID';
      TableName := 'utenti';
      IndexFieldNames := 'ID Asc';
    end;
perchè può NON essere sempre  la stessa.

Mi dispiace chiedere, ma purtroppo non riesco ad andare avanti da solo.
ciao ciao

DragoRosso

  • Scrittore
  • Hero Member
  • *****
  • Post: 1266
  • Karma: +43/-0
  • Prima ascoltare, poi decidere
Re:mie utility su database
« Risposta #13 il: Agosto 27, 2022, 07:31:57 pm »
Nel costruttore della tua classe (TMyUtility) puoi fare solo qualcosa, ad esempio solo istanziare (ossia creare) la connessione senza definire il database ne attivare la connessione stessa. Idem per la ZTable.

Poi puoi definire una funzione dove vai a passare i parametri che preferisci per impostare il database e la connessione.

Ecco, non ho capito come intervenire, perchè è il programma chiamante che conosce il percorso corretto, Ma come faccio a passargli la stringa? Qui?
Codice: [Seleziona]
MiaUtilita := TMyUtility.Create(self, dbOrig)
   

Come ti accennavo puoi creare nuove funzioni in cui passi ciò che vuoi, espandere come hai indicato il costruttore, etc ...

La progettazione di una classe dipende da cosa devi fare e può richiedere anche giorni o settimane per arrivare ad una versione sufficientemente funzionale.

Devi avere ben chiaro:

1) Scopo della classe: esempio generalizza e isola dal codice l'accesso al database... pensa se domani usassi MySql oppure usi qualcosa di diverso da ZEOS, dovresti solo cambiare o meglio implementare la classe e ricompilare senza cambiare una virgola al tua programma.

2) Componenti della classe (chiamati membri): devi prima di tutto definire quali componenti devi avere nella classe (ad esempio quante ZConnection ? quante ZQuery ?). Ovviamente ci dovranno essere anche tutte le variabili di supporto e di stato.

3) Anche se in un primo momento puoi esporre i componenti come "public", magari per facilitare l'accesso al codice vecchia maniera, poi dovrai pian piano definire le proprietà che ti consentano di interagire con le tue Query e le tue Tabelle, proprietà delle classe senza accedere direttamente ai membri interni.

4) Lo stato della classe deve essere sempre congruo, quindi dovrai provvedere a fare si che se usi il multithreading ci siano delle barriere di protezione (per ora è meglio che questo punto lo "appunti" e lo dimentichi).

Hai già sviluppato un applicativo, creare una classe funzionale è il prossimo esercizio, con tanto di procedure funzioni e proprietà.

Giusto per farti capire (il codice è indicativo e non completo):

Codice: [Seleziona]
type
  TMyUtility = Class
  private
      ZConnection1: TZConnection;
      ZTable1: TZTable;
  public
      property ElencoDatabase: TStringList read getElencoDatabase write setElencoDatabase;
      function LeggiLaPrimaRiga: boolean;
      constructor Create(Owner: TComponent); overload;
      destructor Destroy;                    override;
  end;     

C'è una nuova proprietà (che deve essere implementata con una funzione e una procedura "private" ovviamente) che definisce ad esempio il passaggio sia in scrittura che in lettura di quel famoso elenco di nomi dei database. Come vedi è una proprietà e chi la chiama non sà cosa c'è dopo, sà solo che puo passare un elenco di stringhe o ricevere un elenco di stringhe. Sarà la classe a definire come usare questo elenco (sia in ingresso che in uscita).

Per ora basta così ... alla prossima ti chiuderò la proprietà come esempio.

Ciao
:) Ogni alba è un regalo, ogni tramonto è una conquista :)

petrusic

  • Hero Member
  • *****
  • Post: 589
  • Karma: +0/-0
Re:mie utility su database
« Risposta #14 il: Agosto 27, 2022, 11:11:12 pm »
2) Componenti della classe (chiamati membri): devi prima di tutto definire quali componenti devi avere nella classe (ad esempio quante ZConnection ? quante ZQuery ?). Ovviamente ci dovranno essere anche tutte le variabili di supporto e di stato.
Allo stato attuale, tali componenti non mi sono noti, perchè inizialmente sono limitati, ma potranno crescere con le conoscenze e con l'uso che ne deriva dalle necessità legate ai prossimi programmi.

quote author=DragoRosso]
C'è una nuova proprietà (che deve essere implementata con una funzione e una procedura "private" ovviamente) che definisce ad esempio il passaggio sia in scrittura che in lettura di quel famoso elenco di nomi dei database. Come vedi è una proprietà e chi la chiama non sà cosa c'è dopo, sà solo che puo passare un elenco di stringhe o ricevere un elenco di stringhe. Sarà la classe a definire come usare questo elenco (sia in ingresso che in uscita).
Codice: [Seleziona]
      property ElencoDatabase: TStringList read getElencoDatabase write setElencoDatabase;
[/quote]
Per ora non capisco quale sia la sua utilità, perchè m'immagino che una lettura o scrittura su una tabella di DB (sia fisica che logica) si faccia sempre attraverso il trasferimento di una stringa, in formato sql, nella proprieta ZQuery1.SQL.Text, anche se fino ad ora non ho incontrato niente del genere.

Mi pare che tu non mi stia dando un aiuto, ma tutt'altro.
Non voglio tediarti ulteriormente. Ho capito che  Il percorso è lungo ed impegnativo e non mi pare corretto approfittare così tanto della tua disponibilità.

Grazie!

« Ultima modifica: Agosto 28, 2022, 09:35:55 am da petrusic »
ciao ciao

 

Recenti

How To

Utenti
  • Utenti in totale: 785
  • Latest: gmax
Stats
  • Post in totale: 18772
  • Topic in totale: 2233
  • Online Today: 578
  • Online Ever: 900
  • (Gennaio 21, 2020, 08:17:49 pm)
Utenti Online
Users: 0
Guests: 379
Total: 379

Disclaimer:

Questo blog non rappresenta una testata giornalistica poiché viene aggiornato senza alcuna periodicità. Non può pertanto considerarsi un prodotto editoriale ai sensi della legge n. 62/2001.