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

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

Recenti

How To

Utenti
Stats
  • Messaggi totali: 20.582
  • Totale discussioni: 2.471
  • Online today: 310
  • Online ever: 5.949 (Luglio 30, 2026, 09:49:59 PM)
Utenti online
5 Visitatori, 1 Utente

Log

Aperto da cappe, Gennaio 03, 2023, 10:30:19 AM

Discussione precedente - Discussione successiva

cappe

Dovrei fare un log delle modifiche fatte ai database dagli utenti, secondo voi è meglio scriverlo a livello di trigger o di codice pascal. Qualche idea su come o qualche spunto?
Sono orientato di scriverlo in Pascal, ma ci sto pensando ...

nomorelogic

ciao
per farlo a livello di trigger dovresti avere gli utenti che accedono al DB ognuno col loro codice (intendo la connessione al DB)

in uno scenario dove l'applicazione si connette al DB sempre con lo stesso utente e poi l'utente è gestito dall'applicazione è meglio  farlo da codice pascal
Imagination is more important than knowledge (A.Einstein)

Stilgar

#2
Ciao Cappe.

La risposta, come spesso capita in informatica, non è univoca.
Dipende dallo scenario che ti interessa (tanto per cambiare).

Se a te non serve salvare l'utente che opera la modifica, potrebbe essere il trigger che opera la storicizzazione del record modificato, una storicizzazione acefale, per capirsi.
Se devi mettere in piedi una sorta di audit, forse l'utente che opera la modifica ti serve e quindi le strategie devono cambiare (come suggerito da nomore potrebbe non essere lo stesso utente di connessione al db)
Se il DB che utilizzi permette di mettere in sessione dei valori custom, il trigger potrebbe essere ancora una strada praticabile: carici il nome dell'utente che modifica in sessione e il trigger lo legge.

Se a te serve una soluzione che non sia legata mani e piedi ad un engine specifico, la strada dell'applicazione esterna che gestisce l'utenza (come parametro nell'insert, per banalizzare l'operazione) sicuramente è più "portabile" tra i vari engine. Essendo 2 operazioni di modifica (storicizzazione + update) ricordati che devi gestire la transazione.
Storicizzare un record che poi si schianta nella modifica potrebbe portare a delle difficoltà e casini nel caso in cui l'ufficio audit volesse un report delle modifiche.

Spero di averti dato qualche spunto di riflessione.

Stilgar
Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

DragoRosso

Eseguire un Audit delle transazioni di un DB non è cosa semplice. Alcuni DB, anzi dire molti DB, dovrebbero già avere internamente la funzionalità richiesta (tra cui FIREBIRD e MSSQL se non vado errato).

SQLite invece presenta i normali Trigger che possono essere usati per fare creare un log. Però ti leghi specificatamente allo stato del DB e se fai variazioni delle tabelle ad esempio tramite update del tuo applicativo (cosa che ad esempio io faccio) bisogna ricordarsi di aggiornare anche i trigger con delle DDL.

Eseguendo tu a livello di codice i post, commit, etc ... io lo farei con gli eventi propri del componente (ZEOS ad esempio) tipo AfterPOST, AfterCommit, ......

Più flessibile ....

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

nomorelogic

cmq su vuoi passare per i trigger, ti dico come ho fatto io in qualche occasione


  • se possibile, nelle tabelle da "loggare", aggiungi una colonna dove memorizzi l'utente (dell'applicazione) che ha effettuato la modifica e/o l'inserimento
  • creati una stored procedure apposita per inserire i log  (questo ti faciliterà il porting e la manutenzione), così puoi fare il log sia da trigger che da codice pascal
  • nei trigger metti il richiamo alla stored procedure di cui sopra, mantieni il trigger più semplice possibile
  • nella stored procedure, metti l'utente come parametro e leggilo dal campo aggiunto sopra
  • ti rimane fuori l'eliminazione: nel trigger "before update" non c'è un campo utente in quanto il record viene eliminato (quindi non sai chi ha eliminato il record)... ma a questo puoi ovviare richiamando la stored procedure dall'applicazione pascal...
Imagination is more important than knowledge (A.Einstein)

cappe

Il DB è firebird. Grazie per il suggerimento.

Penso di farlo in pascal, Dovrei fare un log delle  modifiche degli utenti. Ma ci sto ancora pensando.
A me serve una cosa semplice.
Tabelle transazione e modifiche. Ci provo.

P.S. Non avevo visto l'altro post sui log anche se sembra essere diverso il contesto,


Stilgar

Allora si può ragione su FB.


https://firebirdsql.org/file/documentation/html/en/refdocs/fblangref30/firebird-30-language-reference.html#fblangref30-ddl-trigger


Utilizzando 2 funzioni FB puoi "personalizzare" la sessione di lavoro dell'utente.


SELECT RDB$SET_CONTEXT ('USER_SESSION', 'OS_USER','UTENTE OS') FROM RDB$DATABASE;


SELECT RDB$GET_CONTEXT ('USER_SESSION', 'OS_USER') FROM RDB$DATABASE;



In questo modo puoi customizzare le sessioni e lavorare con i trigger, generalizzare le tue query (da pascal), adattare la "stored procedure" senza dover sempre pescare l'utente dal sistema operativo.


(Salvi e riusi in altre parole)


Stilgar


Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

Stilgar

Per migliorare il suggerimento di nomore.
Se duplichi la struttura che devi mettere sotto audit, e aggiungi la colonna utente + operazione, puoi utilizzare 3 valori (quindi aggiungi anche il tipo di manipolazione del record che viene operato).
0=Insert
1=Update
2=Delete
(o una cosa similie).
Così puoi tracciare anche le cancellazioni, oltre che le versioni del record con tutte le modifiche operate sulla singola riga.


Poi, se aggiungi la data inizio validità e fine validità, puoi tenere traccia anche quando è stato modificato il record sotto audit.


Quindi la logica dovrebbe essere:
1) Chiudere la validità del record storicizzato precedente, con il codice di modifica che hai utilizzato + utente, se presente (l'update può lavorare anche se il record no è presente, senza far scattare errori)

update {tabella}_storico set data_validita_fine = CURRENT_TIMESTAMP, mod_code={codice_modifica} where data_validita_fine  is null

una cosa del tipo
2) Modificare/Inserire/Eliminare il record d'interesse.


3) Copiare il record attuale in quello storico

insert {tabella}_storico select *, CURRENT_TIMESTAMP, null, null from {tabella}


Le query sono di esempio, non so se funzionano così come le ho messe (non maledirmi)


Stilgar

Stilgar.
Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

cappe

Ok. Domani provo a farlo.

cappe

#9
Citazione di: Stilgar il Gennaio 03, 2023, 06:20:51 PM
Per migliorare il suggerimento di nomore.
Se duplichi la struttura che devi mettere sotto audit, e aggiungi la colonna utente + operazione, puoi utilizzare 3 valori (quindi aggiungi anche il tipo di manipolazione del record che viene operato).
0=Insert
1=Update
2=Delete
(o una cosa similie).
Così puoi tracciare anche le cancellazioni, oltre che le versioni del record con tutte le modifiche operate sulla singola riga.
Poi, se aggiungi la data inizio validità e fine validità, puoi tenere traccia anche quando è stato modificato il record sotto audit.

Quindi la logica dovrebbe essere:
1) Chiudere la validità del record storicizzato precedente, con il codice di modifica che hai utilizzato + utente, se presente (l'update può lavorare anche se il record no è presente, senza far scattare errori)

update {tabella}_storico set data_validita_fine = CURRENT_TIMESTAMP, mod_code={codice_modifica} where data_validita_fine  is null

una cosa del tipo
2) Modificare/Inserire/Eliminare il record d'interesse.


3) Copiare il record attuale in quello storico

insert {tabella}_storico select *, CURRENT_TIMESTAMP, null, null from {tabella}


Le query sono di esempio, non so se funzionano così come le ho messe (non maledirmi)


Stilgar

Stilgar.

Grazie.
Fatto e funziona. La cosa interessante è che hai la fotografia della tabella, però come contro ricopia ogni volta tutti i dati. La cosa carina è che è semplice e sembra funzionare e molto probabilmente lo utilizzerò.

Ora provo con solo le modifiche.

Stilgar

Son contento che l'idea ti piaccia.
Tieni conto che ho preso l'approccio più ignorante (o agnostico se vogliamo parlare erudito) possibile.


Un problema di questo approccio è lo spazio.
Ricordati di mettere gli indici anche sulle date validità. Altrimenti con il tempo cercare nello storico diventa un massacro a livello di tempi.


Per le ottimizzazioni del db cedo il passo a Nomore che ha più esperienza di me.


Stilgar.
Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

cappe

ad ogni modo, grazie e una buona idea

nomorelogic

per ora farei una riflessione sulla PK della tabella dello storico

se storicizziamo ad esempio un cliente, questo comparirà N volte nella tabella storico_clienti
per questo se impostiamo la PK come chiave composta con i campi:

  • codice cliente
  • data inizio validità (potrebbe essere "fine_validità" poi uno ragiona come vuole)

avremo il doppio vantaggio di (1) avere la possibilità di memorizzare N volte lo stesso cliente con la data di validità come discriminante e (2) una PK è anche un indice....

resta da capire come fare se la storicizzazione viene lanciata più volte  per lo stesso cliente nello stesso giorno
però la soluzione è semplice: basta che la data di validità sia un timestamp


Imagination is more important than knowledge (A.Einstein)

Stilgar

Infatti nelle query suggerite ho messo current_timestamp().
Solo DATE mi ha creato grosse rogne in passato nella storicizzazione con operazioni parallele.


Stilgar.




Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

nomorelogic

ops... a forza di parlare di "data" avevo dimenticato lo script  ::)
Imagination is more important than knowledge (A.Einstein)

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.