.. _orm_genropy/approfondimenti/accesso_concorrente: Accesso concorrente =================== In caso di utilizzo contemporaneo del *db* da parte di più utenti, l'ORM mette a disposizione una serie di strumenti atti a gestire l'accesso concorrente al record. Il parametro *for_update=True* ------------------------------ In una qualsiasi :ref:`Operazione di lettura` è possibile richiedere la restituzione del record a scopo di successiva modifica semplicemente passando il parametro ``for_update=True``:: rec_trapano = tbl_prodotto.record(where='$codice=:cod_prod', cod_prod='T1', for_update=True).output('dict') A questo punto sarà possibile modificare il rec_trapano come segue:: old_record = dict(rec_trapano) rec_trapano['prezzo_unitario'] = rec_trapano['prezzo_unitario'] * 3 Ed effettuare *update* e *commit* come descritto al paragrafo precedente. .. hint:: Si noti che prima di effettuare la modifica facciamo una copia del record costruendone un dizionario (*old_record*). Questo passaggio non è obbligatorio ma è buona consuetudine per innescare determinati eventi di business logic, per esempio nei :ref:`trigger` recordToUpdate ~~~~~~~~~~~~~~~ In caso di necessità di modifica di **un solo record**, esiste una scorciatoia all'operazione di semplice *update*:: with tbl_prodotto.recordToUpdate(codice='T1') as rec_prodotto: rec_prodotto['prezzo_unitario'] = rec_prodotto['prezzo_unitario'] + 1 mydb.commit() In questo caso viene sfruttato il concetto di *Context Manager* nativo di Python: viene così automaticamente effettuata l' :ref:`Operazione di lettura` , che restituisce un record già pronto per la modifica, e non si rende necessaria l'esplicitazione dell'*update*, ma solo il *commit* finale. Come in una qualsiasi :ref:`Operazione di lettura` la *recordToUpdate* può ricevere, alternativamente alla condizione *where*, anche una ``pkey``. .. hint:: Arricchendo la ``recordToUpdate`` con l'attributo ``ignoreMissing=True``, evitiamo di mandare il sistema in errore in caso mancasse il record da aggiornare, mentre con ``raw=True`` verrà effettuato l'update ignorando eventuali :ref:`Trigger` batchUpdate ----------- La ``batchUpdate`` è una funzione messa a disposizione da Genropy per accorciare l'operazione di *update* di **molti record risultato di una query**: in questo modo, invece di ripetere l'operazione di modifica per *ogni* singolo record risultato della query, è possibile effettuare la modifica su tutti i record contemporaneamente. Quindi, ad esempio, invece di applicare la modifica all'interno di un ciclo *for*:: prodotti = tbl_prodotto.query(where='$descrizione ILIKE :desc' , desc='Tavolo%', for_update = True).fetch() for p in prodotti: old_rec = dict(p) p['prezzo_unitario'] = 49 tbl_prodotto.update(p, old_rec) È possibile sfruttare la *batchUpdate*:: tbl_prodotto.batchUpdate( dict(prezzo_unitario = 49), where='$descrizione ILIKE :desc', desc='Tavolo%') In questo caso stiamo passando al metodo un **updater "statico" sotto forma di dizionario** contenente il nuovo campo, mentre in casi più complessi è possibile passare alla *batchUpdate* un **updater "dinamico" sotto forma di metodo** *callback* definito precedentemente:: def myupdater(rec): if rec['prezzo_unitario'] < 100: rec['prezzo_unitario'] = rec['prezzo_unitario'] + 11 else: rec['prezzo_unitario'] = rec['prezzo_unitario'] - 5 updated_pkeys = tbl_prodotto.batchUpdate(myupdater, where='$descrizione ILIKE :desc', desc='Tavolo%') mydb.commit() Come in una qualsiasi :ref:`Operazione di lettura` la *batchUpdate* può ricevere, alternativamente alla condizione *where*, una lista di ``pkeys``, così come possono essere **richieste delle colonne specifiche** necessarie poi all'interno del metodo *updater*:: updated_pkeys = tbl_prodotto.batchUpdate(myupdater, where='$descrizione ILIKE :desc', columns='*,@classe_iva.aliquota, desc='Tavolo%') .. hint:: Arricchendo la ``batchUpdate`` con l'attributo ``ignoreMissing=True``, evitiamo di mandare il sistema in errore in caso mancassero record da aggiornare, mentre con ``_raw_update=True`` verrà effettuato l'update ignorando eventuali :ref:`Trigger` Al termine dell'operazione ritornerà comunque sempre le *pkeys* dei record modificati. .. sectionauthor:: Davide Paci