It is currently 26 February 2021, 18:24 Advanced search

globalizzare un campo di database

Domande e risposte su come utilizzare Instant Developer Foundation al meglio

globalizzare un campo di database

Postby theguru » 20 February 2021, 19:41

Vorrei che tutte le mie tabelle avessero alcuni campi "in comune", intendo "identici per tutte"
Il mio problema però non è creare tali campi, lo faccio senza problemi duplicandoli manualmente dall'una all'altra.
Ma vorrei che le proprietà derivate potessero essere elaborate e gestite da procedure globali, mi chiedo quale sia la strada migliore.

Detta in un altro modo, è possibile creare i propri servizi generalizzati di inde (tipo user_info, logical_deletion etc..) associandoli a campi di database personalizzati?

Spiegazione più dettagliata (tramite esempio):
- mi invento un servizio "ordinamento_manuale"
- quindi ogni tabella (associata ad un doc che dovrà utilizzare questo servizio), avrà un campo int chiamato list_order
- un altra classe, che contiene la collection di documenti definiti sopra, ha tutto il codice necessario per spostare in su o in giù i vari documenti a pannello, memorizzando poi l'ordine dentro il campo (la proprietà) list_order dei doc figli
- ora, io vorrei globalizzare l'algoritmo, ad esempio, estendendo una classe che contiene tale codice
- il problema pratico è quello che le proprietà che derivano dal db sono presenti nelle singole classi, e non possono essere "guidate" tramite overload, detto in altro modo, procedura globale che utilizza una variabile list_order globale non tocca le variabili list_order delle singole classi estese (che derivano dal db)

Ora, qualche soluzione mi viene in mente, come quella di globalizzare nell'afterload del document_helper una procedura che cerchi la proprietà in esame tramite reflection, la assegni a quella globalizzata, ed esegua l'operazione inversa al momento del salvataggio. Tuttavia mi sembra un approccio macchinoso, considerando che il 99 ,9 % delle volte tale funzione non sarà utilizzata, ed andrebbe ad appesantire il load di ogni documento (o magari collection) a livello generale.

Ho la sensazione di perdermi una soluzione ben più immediata e diretta
Avete qualche suggerimento, qualche idea sulla best practice in tal senso?

EDIT: ok, un mezzo uovo di Colombo, nel senso che per ora mi rimane ancora un po' quadrato: esplicito per ogni classe la master query, e dentro questa sostituisco le proprietà della classe estesa con quelle della classe base. ma esiste un modo semplice per globalizzare la cosa? intuisco che i domini potrebbero aiutare, ma non saprei come..
User avatar
theguru
 
Posts: 862
Joined: 29 January 2014, 13:01

Re: globalizzare un campo di database

Postby r.bianco » 22 February 2021, 7:42

theguru wrote:Ma vorrei che le proprietà derivate potessero essere elaborate e gestite da procedure globali, mi chiedo quale sia la strada migliore.


Noi applichiamo lo stesso dominio con concetto a tutti i campi che vogliamo vengano trattati nello stesso modo.
Negli eventi globali, facciamo un giro sulla struttura del documento e, in base al concetto, eseguiamo le procedure del caso.
only work and no play makes jack a dull boy
r.bianco
 
Posts: 4363
Joined: 8 November 2010, 16:46

Re: globalizzare un campo di database

Postby theguru » 22 February 2021, 13:54

r.bianco wrote:Noi applichiamo lo stesso dominio con concetto a tutti i campi che vogliamo vengano trattati nello stesso modo.
Negli eventi globali, facciamo un giro sulla struttura del documento e, in base al concetto, eseguiamo le procedure del caso.

Si, mi è chiaro. In certi contesti tuttavia questo "giro sulla struttura" potrebbe diventare pesante, a livello di esecuzione, se dovesse essere applicato ad ogni load. Potrei mettere un semaforo... dovrei ragionarci meglio.

A beneficio di chi capiterà da queste parti, propongo una soluzione alternativa:

Intanto, l'idea di esplicitare la master query di caricamento è alla lunga fallimentare: troppo error prone, introduce nel progetto zone da mantenere per nulla centralizzate, oltretutto c'è un piccolo malfunzionamento dell'intellisense che impedisce la modifica di alcune query via codice, costringendoti al drag'n'drop. Dulcis in fundo, funziona nella fase di load, ma inde non tiene traccia della query di caricamento quando si tratta di scrivere il doc sul db, quindi nessun "update" automatico.

Invece, usando l'overload dei metodi, a me tanto caro, inserisco negli eventi after_load e before_save della classe genitrice due procedure vuote (gg_after_load() & gg_before_save() rispettivamente) che sovrascrivo per ogni classe (tanto, ogni classe ha già la propria cartella Overload con una decina di procedure, un paio in più non mi incasinano il codice). Il metodo sovrascritto altro non fa che copiare banalmente proprietà locali su quelle gloabali e viceversa.
Per ora testato tutto e funziona :)
Ma resto sempre in ascolto per approcci migliori!
User avatar
theguru
 
Posts: 862
Joined: 29 January 2014, 13:01

Re: globalizzare un campo di database

Postby t.simoncini » 22 February 2021, 14:39

Ormai che ci sono te ne dico un'altra. Non so però se sia meglio o peggio.

Puoi utilizzare l'overload dei metodi per farti ritornare da ogni classe derivata quali sono gli indici delle proprietà che ti interessano, e poi usare nella classe base i metodi SetPropery e GetProperty. In questo modo hai le proprietà una volta sola, sulle classi derivate, e la logica te la tieni sulla classe base.
Puoi anche provare con la GetPropertyIndex magari usando un concetto, però se la PropertyDefinition ti crea problemi di performance, non so se ne vale la pena.

PS. I tuoi dubbi di pesantezza sono derivanti da test? Giusto per curiosità. Così "a pelle" mi verrebbe da pensare che non debbano rallentare troppo. Sono tutti oggetti in memoria. Ammesso che tu non debba inizializzare decine di migliaia di documenti (con centinaia di proprietà), non so quanto possa effettivamente rallentare.
t.simoncini
 
Posts: 1162
Joined: 5 March 2012, 14:00

Re: globalizzare un campo di database

Postby zpj61 » 23 February 2021, 7:19

Se ti può essere utile posso riportarti quello che ho fatto per rendere globale e assolutamente trasparente a inde una crittografia selettiva su alcuni campi di database. Per trasparente intendo lettura e scrittura di documenti senza preoccuparsi di se crittografati o no ovvero all'interno del documento il dato è in chiaro, all'esterno cioè su db è crittato, il tutto in maniera trasparente e senza usare crittografia del db engine. Si è partiti definendo un dominio da applicare ai campi da crittografare e ti puoi sbizzarrire definendo anche domini diversi per diversi tipi di crittografia...
Si è definito poi un document helper con eventi globali after load, before save, e after save dove vengono cercate le proprietà del documento ed il loro concetto. Se il concetto è quello del dominio si applica la crittografia ovvero un componente crypter nel nostro caso legato ad una libreria esterna oppure al simplecrypter di inde. Non è esattamente il tuo caso ma il concetto è rendere le cose trasparenti ai meccanismi documentali di CRUD. Dalle prove fatte nell'uso comune l'overhead non si vede né sul client né sul server.
User avatar
zpj61
 
Posts: 723
Joined: 20 November 2015, 8:20
Location: Bassano del Grappa

Re: globalizzare un campo di database

Postby theguru » 23 February 2021, 21:49

Ok, per prima cosa ringrazio davvero tutti per i contributi, sostanzialmente mi avete fatto capire che l'algoritmo da me ipotizzato era quello.. corretto, immagino secondo le indicazioni di progamma: ovvero assegnare i domini e loopare sulle proprietà al momento del load/save, replicando i valori nelle proprietà della classe base.

Ora, vorrei dare il mio contributo anche io, ed inizio col dire che in molte occasioni utilizzando il farmework (inde) ho notato come gli overload di metodi, forse proprio perché gestiti direttamente dal compilatore C# o Java, fossero più efficienti di soluzioni (anche di alto livello) proposte dal framework stesso (un esempio: la malefica funzione .docId() !)

e quindi... ho fatto i benchmark :)
Banalmente carico in memoria un blocco di 100.000 (100k) record, con le seguenti modalità:

A) load_collection_from_db() senza fronzoli, nessun after_load di alcun tipo

B) come sopra, ma questa volta tramite overload lancio un metodo nella classe figlia (estesa) che copia le proprietà sulla classe base:
Screen Shot 2021-02-23 at 21.31.34.png
Screen Shot 2021-02-23 at 21.31.34.png (12.38 KiB) Viewed 35 times


C) come al punto A) ma questa volta utilizzo il global_after_load per loopare le proprietà, trovare i domini, e copiare le proprietà sulla classe base

D) come al punto A) ma questa volta utilizzo la funzione GetPropertyIndex(), specificando la ricerca per concetti, trovo gli indici e copio le proprietà come nei casi precedenti

Queste le procedure C e D il blocco non utilizzato veniva commentato:
Screen Shot 2021-02-23 at 21.31.59.png
Screen Shot 2021-02-23 at 21.31.59.png (104.23 KiB) Viewed 35 times

NOTA: per semplificarmi la vita ho fatto tutto su cassini, ma con i debug disattivati in modo simulare un ambiente di produzione.

(rullo di tamburi)
Risultati:
A) tempo medio su 10 run: 4,5 secondi (overhead: 0 sec)
Screen Shot 2021-02-23 at 20.39.13.png
Screen Shot 2021-02-23 at 20.39.13.png (8.57 KiB) Viewed 35 times


B) tempo medio su 10 run: 5,1 secondi (overhead: 0.6 sec)
Screen Shot 2021-02-23 at 20.51.00.png
Screen Shot 2021-02-23 at 20.51.00.png (9.79 KiB) Viewed 35 times


C) tempo medio su 10 run: 33,2 secondi (overhead: 28,7 sec)
Screen Shot 2021-02-23 at 21.03.11.png
Screen Shot 2021-02-23 at 21.03.11.png (10.35 KiB) Viewed 35 times


D) tempo medio su 20 run: 6.5 secondi (overhead: 2 sec)
Screen Shot 2021-02-23 at 21.11.58.png
Screen Shot 2021-02-23 at 21.11.58.png (10.14 KiB) Viewed 35 times
L'ultimo test è stato eseguito 20x in quanto i risultati presentavano una varianza molto maggiore dei precedenti

Conclusioni:
1) il loop sulle proprietà ha performance catastrofiche: chiaro, se qualcosa è istantaneo, 6x istantaneo è sempre percepito come istantaneo. ma bisognerebbe anche ragionare in questo modo:
La mia app (esempio) sta su un EC2, esegue crud (load and save) per, ipotizziamo, metà del suo ciclo di utilizzo cpu, l'istanza del db è tariffata separatamente: il mio utilizzo di cpu sarà superiore di un valore compreso tra i rapporti (28,7/0,6)/2, ovvero quasi 24 volte tanto, e (33,2/5,1)/2, ovvero 3,25 (abbastanza spostato verso il 24, considerando che i tempi del db sono maggiori di quelli usati da inde per popolare le istanze di documenti, esclusi i loop su proprietà) ...immaginate la differenza in fattura aws.
2) l'overload resta comunque la strada più performante
3) la funzione GetPropertyIndex() mi ha stupito in positivo, immaginavo si comportasse peggio
4) bisogna anche considerare un altra cosa: l'overload non è centralizzato come il global_after_load, ma "sporca" pochissimo il codice, ed è facilissimo personalizzare per ogni classe, direttamente dentro la classe!
Usando il global_afterload di IDdocumentHelper, dovrei utilizzare il if(mia_classe_estesa.is_my_instance(doc)) {...} all'interno, ma se il document helper si trova dentro un componente BASE, o CORE, o quello che volete, si genereranno referenze circolari: quindi è necessario definire una classe helper e una variabile diversa per ogni n-esimo componente. Immagino si possa fare, ma escludendo la manutenibilità del codice un po' peggiore, bisogna considerare che probabilmente verranno chiamati n global_after_load, uno per ogni componente, con conseguente aumento di (quasi) n dell'overhead relativo.

Ok, ho scritto un poema, ma spero di essere utile qualcuno, riassumendo, overload forever ti lovvo di brutto.
ciao!
User avatar
theguru
 
Posts: 862
Joined: 29 January 2014, 13:01

Re: globalizzare un campo di database

Postby t.simoncini » 24 February 2021, 7:47

Interessante.
Grazie della condivisione.
t.simoncini
 
Posts: 1162
Joined: 5 March 2012, 14:00


Return to Tips & Tricks - Foundation

Who is online

Users browsing this forum: No registered users and 14 guests