Durante la fase di Refactoring abbiamo definito due nuovi metodi nel servizio infrastrutturale IDatabaseAccessor.cs che ti mostro con una immagine, prima però voglio illustrarti brevemente quali saranno gli argomenti di questo post. Parleremo del problema della concorrenza, ossia quando due utenti cercano di modificare contemporaneamente le stesse informazioni, e vedremo che ci sono due approcci per affrontare il problema, la concorrenza pessimistica e la concorrenza ottimistica. In questo progetto utilizzeremo il secondo approccio.
I metodi in questione sono QueryScalarAsync<T> e CommandAsync, questi metodi che fanno parte della fase di progettazione ora vanno implementati nella classe SqliteDatabaseAccessor.cs.
Vediamo come si inviano comandi con ADO.NET.
Anche leggere un risultato scalare è un’operazione altrettanto semplice.
Questo è il codice implementato.
EVITARE SOVRASCRITTURE ACCIDENTALI CON LA CONCORRENZA OTTIMISTICA
Nel momento in cui l’applicazione verrà messa in produzione, verrà usata da più utenti contemporaneamente, supponiamo che nella scheda di modifica del corso arrivino sia il docente che un suo assistente, se il docente fa delle modifiche che vengono rese persistenti nel database e subito dopo anche l’assistente modifica il Form, ebbene tutto il lavoro del docente verrebbe sovrascritto. Una prima soluzione ci viene offerta dalla concorrenza pessimistica.
Il vantaggio nell’usare questa tecnica è che l’assistente viene tempestivamente avvisato che un altro utente sta modificando il Form su cui detiene un accesso esclusivo, lo svantaggio è che l’assistente non sa quando deve tornare per apportare le sue modifiche. Se volessimo implementarla dovremmo aggiungere due nuove colonne nella tabella Courses.
Per quanto riguarda il LockedUntil a quanto dovremmo impostare questa data nel futuro? Qualsiasi valore scegliamo sarà inappropriato in quanto non possiamo sapere per quanto tempo il docente rimarrà su quel corso. Quello che si può fare è questo, se la pagina è ancora aperta si imposta una scadenza di un minuto nel futuro, se tra un minuto la pagina è ancora aperta si invia un’altra richiesta AJAX che la proroga ancora di un minuto e così via fino a quando il docente lascia la pagina.
LE RICHIESTE AJAX
Questo tipo di soluzione si può prestare ad abusi perché se il docente non vuole che nessuno modifiche la pagina gli basterà tenerla aperta tutto il giorno. Quello che implementeremo noi sarà la concorrenza ottimistica. RowVersion contiene la data e ora dell’ultima volta che il corso è stato aggiornato o inserito.
L’importante è che il valore di RowVersion venga letto nel Form, non deve essere visibile, può essere implementato come campo hidden, la nostra applicazione consentirà il salvataggio del Form soltanto se il valore nel Form coincide con quello nel database.
AGGIORNARE IL VALORE DI ROWVERSION
Nel momento in cui il docente aggiorna il corso viene aggiornato anche il valore di RowVersion sul database con la stessa data e ora dell’ultimo salvataggio. Se Luigi Verdi tenta di fare una modifica non ci riuscirà perché il valore nel Form non coincide con quello nel database in quanto Mario Rossi ha modificato e salvato il Form.
Vediamo cos’è un Trigger.
NEW.Id accede all’ultimo Id inserito.
IMPLEMENTARE LA CONCORRENZA OTTIMISTICA CON ADO.NET ED EFCORE
I valori di RowVersion come visto si aggiornano automaticamente quando una nuova riga viene inserita o viene fatto l’aggiornamento di una esistente. Se RowVersion ha lo stesso valore del campo hidden del Form allora si procede con il salvataggio altrimenti si notifica all’utente un messaggio.
Vediamo ADO.NET.
Guarda l’implementazione in AdoNetCourseService.cs, EfCoreCourseService.cs, nel CoursesController.cs e nella View di Edit dove è stato aggiunto il campo nascosto. Vediamo il caso di EFCore.
LINK AL CODICE SU GITHUB
Scaricare il codice della sezione16 oppure il ramo master o clonare il repository GITHUB per avere a disposizione tutte le sezioni nel tuo editor preferito.
Scrivi un commento