In una applicazione gestionale c’è sempre l’esigenza di gestire le modifiche contemporanee su di un record da parte di più utenti e con Instant Developer Foundation lo possiamo fare in modo semplice.
Il nostro scopo è fare in modo che se un record è in stato di modifica, quindi un utente ha modificato almeno un suo campo o un campo di un record figlio gli altri utenti non possano effettuare a loro volta modifiche ma vengano informati della situazione con un messaggio a video.
Per risolvere questo problema di solito occorre scrivere molto codice ma Instant Developer Foundation ci viene in aiuto con il Document Helper la classe che viene utilizzata per rendere globali gli eventi dei documenti, un paio di eventi e l’attivazione della proprietà Document lock sul documento.
Quindi la gestione dei lock posso attivarla solo sui documenti per i quali mi interessa farlo.
Gli eventi che ci interessano sono due:
- GetLock - prende un lock su un documento
- ReleaseLock - rilascia un lock su un documento
Oltre a questo ci occorre una tabella dove memorizzare i lock attivi, che sarà composta da questi campi:
- Id - la pk del record
- DNADoc - il DNA del documento su cui si è preso il lock
- DataOra - la data e ora del lock
- UtenteLock - l’utente che ha preso il lock
Cos’è il DNA di un documento? È il suo identificativo univoco che contiene i valori della chiave primaria il nome del documento e in quale componete sta.
Per esempio la stringa "CommonDoc$Order",10248 indica il documento Order del componente CommonDoc con chiave 10248.
L’evento GetLock viene notificato non appena un utente da un pannello modifica un campo del documento presente o di uno dei suoi documenti figli.
In questo evento mi viene passato il documento come IDDocument e quindi posso prelevare il suo DNA e verificare se nella tabella dei lock è presente un record di lock di un utente che non è quello loggato cosi da poterlo segnalare a video.
Per farlo devo impostare a false il parametro di output Result e utilizzare il parametro LockInfo per indicare il messaggio che verrà portato in automatico dal framework sulla videata.
Nel caso che non sia presente un lock dovrò scrivere un record nella tabella dei lock.
Per i lock che rimangono appesi perché non è stato completato il ciclo di modifica mediante salvataggio o annullamento del lock, perché la sessione è scaduta, si può aggiungere una verifica sulla data e ora di presa del lock e gestire e definire quale intervallo di tempo si considera per mantenere il lock.
Qui di seguito il codice dell’evento GetLock.
event DocHelper.GetLock(
IDDocument Doc
string UserInfo
inout string LockInfo
inout boolean Result
)
{
Lock l = Lock.checkLock(Doc.getDNA())
boolean creaLock = false
//
// Nessuno ha un lock
if (l == null)
{
creaLock = true
Result = true
}
else // Esiste un lock
{
// Il lock è preso dallo stesso utente allora aggiorno l'orario ad adesso
if (l.UtenteLock == CommonDoc.userName)
{
l.DataOra = now()
l.saveToDB(...)
Result = true
}
else //
{
float minuti = (now() - l.DataOra) * 24 * 60
//
// Considero il lock obsoleto se sono passati 30 minuti dal suo inizio
if (minuti > CommonDoc.TempoDurataLock)
{
l.deleted = true
l.saveToDB(...)
creaLock = true
Result = true
}
else // Il documento è ancora in lock e lo comunico
{
LockInfo = formatMessage("Il documento risulta bloccato dall'utente |1 - Non puoi apportare modifiche (riprova più tardi ricaricando i dati)", l.UtenteLock, ...)
Result = false
}
}
}
//
// Creo il lock
if (creaLock)
{
Lock newLock = new()
newLock.init()
newLock.DNADoc = Doc.getDNA()
newLock.DataOra = now()
newLock.UtenteLock = CommonDoc.userName
newLock.saveToDB(...)
}
}
Per rilasciare il lock viene notificato l’evento ReleaseLock dove cancelliamo il record dalla tabella dei lock. Questo il suo codice:
event DocHelper.ReleaseLock(
IDDocument Doc
)
{
Lock l = new()
l.DNADoc = Doc.getDNA()
//
try
{
l.loadFromDB(...)
l.deleted = true
l.saveToDB(...)
}
catch
{
l = null
}
}
Cosa ne pensate?
Potente vero?
Vi allego un esempio funzionante che realizza la cosa
Gestione Lock.zip (1,6 MB)