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 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.

Suggerimento

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 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” 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 Operazione di lettura la recordToUpdate può ricevere, alternativamente alla condizione where, anche una pkey.

Suggerimento

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 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 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%')

Suggerimento

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 Trigger

Al termine dell’operazione ritornerà comunque sempre le pkeys dei record modificati.

Autore della sezione: Davide Paci