Aggiornare Oggeto leggendo da DB

martedì 10 novembre 2009 - 15.20

Teech Profilo | Expert

Ho una situazione di questo tipo:
- Ho un DataTable popolato con dei dati presi da un Database SQL (AgentsTable)
- Ho una Collection (Agents) che esegue il parsing del DataTable e per ogni DataRow crea un oggetto (Agent) a tipizzazione forte
- Lo scenario è di diversi client che possono accedere al DB.

Poniamo che avvengano le seguenti operazioni in sequenza:
Ore 8:00 - L'utente A apre una form dove viene caricata la collection Agents.
Ore 8:10 - L'utente B effettua la stessa operazione.
Ore 8:20 - L'utente B apre un Agent e ne modifica un dato e salva
Ore 8.25 - L'utente A apre l'Agent precedentemente modificato dall'utente B

Ora, non ho problemi con la gestione del DB in quanto ho già implementato le varie logiche utilizzando i Timestamp (in concorrenza vince il primo), ma come posso aggiornare la collection dell'utente A di modo che possa vedere la variazione? Esiste un pattern o qualche struttura già collaudata per gestire queste situazioni?

Grazie mille...
--------------
Maurizio Brini
--------------
Nessuna impresa è mai stata compiuta da un uomo ragionevole

Jeremy Profilo | Guru

Ciao Maurizio.
Potresti generare un evento che notifica (all'utente B) la modifica della collezione da parte dell'utente A .... sarà poi onere dell'utente B dover ricaricare i dati dal Db per ottenere i dati aggiornati.
Bisognerebbe conoscere bene lo scenario della tua applicazione ma, nel peggiore dei casi, per generare l'evento, potresti incrementare un valore intero depositato in una tabella del Db, costantemente monitorato da un Thread separato.

Facci sapere....
Ciao

alx_81 Profilo | Guru

Ciao
>Ora, non ho problemi con la gestione del DB in quanto ho già
>implementato le varie logiche utilizzando i Timestamp (in concorrenza
>vince il primo), ma come posso aggiornare la collection dell'utente
>A di modo che possa vedere la variazione? Esiste un pattern o
>qualche struttura già collaudata per gestire queste situazioni?
Aggiungo una possibile soluzione. Potresti pensare di utilizzare WCF (Windows Communication Foundation) che ti permette di tenere un layer centralizzato per smistare le chiamate. In questo modo, è sufficiente che la tua applicazione richiami n volte il livello di business (come un poller) ogni "tot" tempo per ricavare il nuovo datatable. In più, ti fai passare la data di ultima modifica in modo da gestire un livello di cache per evitare inutili rendering se i dati non sono modificati.
Quindi:
- l'utente A fa il suo primo accesso e carica il datatable mettendolo in memoria cache (con una data di modifica dei dati) andando a renderizzare la griglia degli agents
- l'utente B fa il suo primo accesso e carica il datatable mettendolo in memoria cache (con una data di modifica dei dati) andando a renderizzare la griglia degli agents
- l'utente B apre, modifica e salva un agent (cambia la data di modifica dei record ed invalida la sua cache per caricare il nuovo source)
- tutti gli utenti hanno un ipotetico poller a timer che ogni tanto richiede la data di modifica dei record, se è cambiata carica i nuovi dati sul datatable
- l'utente A, facendo polling si accorge che la data è cambiata e quindi carica il resultset nuovo dando un notifica per scatenare l'evento di refresh dei dati.
che ne pensi?

>Grazie mille...
di nulla!
--

Alessandro Alpi | SQL Server MVP

http://www.alessandroalpi.net
http://blogs.dotnethell.it/suxstellino
http://mvp.support.microsoft.com/profile/Alessandro.Alpi
http://italy.mvps.org

Teech Profilo | Expert

Intanto vi ringrazio tantissimo per le risposte.
Lo scenario in cui opero è il seguente: All'apertura della mia applicazione visualizzo una serie di DataGridView che che vengono popolate attraverso delle classi Collection che a loro volta vengono popolate da degli Adapter (ogni Adapter corrisponde ad una DataTable). Il mio problema è che la chiamata per popolare queste DataGridView avviene alla prima apertura dell'applicazione e poi basta (per ora) quindi, in un ambiente scollegato come quello di ADO.NET non ho modo di recepire le eventuali variazioni apportate ai dati da altri utenti sullo stesso database. Facendo doppio click su un record in uno di questi DataGridView apro una TabPage in un TabControl visualizzando il dettaglio del record.
Attualmente utilizzo ancora il framework 2.0, quindi escludo WCF (non per volontà, ma per mancanza di produttività).

L'idea che mi è venuta è la seguente:
Quando popolo il DataTable memorizzo in una propietà il valore massimo dei timestamp attualmente contenuto nella tabella: utilizzo una classe che eredita da DataTable, quindi ho flessibilità in questo senso ma in ogni caso si possono usare le ExtendedProperty del DataTable.
A questo punto ho un riferimento per sapere quali record sono stati variati dopo l'ultimo accesso.

Fatto ciò divido la logica di controllo di aggiornamento dei dati in 2 metodi separati sull'Adapter:
- Il primo metodo che accetta un oggetto Datarow ed esegue una SELECT sul DB cercando il record a parità di chiave primaria ed un timestamp maggiore di quello memorizzato per il Dataow: se trova il record aggiorno i dati e li visualizzo aggiornati (per i record updated da altri utenti). Questo metodo lo gestirò attraverso degli eventi sulla classe Collection.
- Il secondo che effettua una select considerando tutti i record con un timestamp maggiore di quello memorizzato per la tabella: in questo modo posso aggiornare i record, inserire quelli nuovi e per compensazione cancellare quelli non più presenti sul database.

Il discorso sembra stare in piedi (detta così) però mi ritrovo con un paio di problemi da gestire per la logica del secondo metodo.
In primo luogo devo capire come utilizzare i Thread per utilizzare il secondo metodo: per lo scenario in cui utilizzo questo metodo dovrei impostare un agent in backgound e thread separato che effettua le scansioni sul DB. Non ho mai usato i thread (anche se li ho "studiati") e devo capire bene come comportarmi: è il caso di utilizzare un timer o ci sono tecniche più "pulite" per effettuare ciò con il framework 2.0? Avete consigli su come gestire questo aspetto?
Il secondo problema, molto più semplice, sarà il discorso della gestione dei record cancellati sul DB, ma per questo devo ancora pensare a qualcosa e credo troverò una soluzione.

Pensate possa funzionare? Se si, avete consigli su come impostare il thread per l'utilizzo del secondo metodo?
Grazie ancora...

P.S.: non pensavo che questo tipo di scenario di multiutenza potesse complicarsi così ma credo sia un aspetto "interessante" da discutere...
--------------
Maurizio Brini
--------------
Nessuna impresa è mai stata compiuta da un uomo ragionevole

Jeremy Profilo | Guru

Ciao Maurizio.
La soluzione che hai pensato tu non sia llontana molto da come l'avevo pensata io ...ma è sicuramente la migliore di tutte, in quanto .... l'hai pensata tu e quindi ti verrà più facile metterla in pratica.
Mi sembra di capire però che hai dei problemi con la gestione in multi Threading ..... riguardo a questo ti posso dire che, per quel poco che ti conosco, sarà più semplice di quanto pensi.
Ad ogni modo .... rimango a disposizione per ulteriori info a riguardo.
Facci sapere...
Ciao.

Teech Profilo | Expert

Effettivamente ho preso spunto dai vostri suggerimenti
Lascio aperto il thread perchè credo che avrò sicuramente bisogno di altri consigli prima di chiudere il discorso

Per ora grazie!!!
--------------
Maurizio Brini
--------------
Nessuna impresa è mai stata compiuta da un uomo ragionevole
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2024
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5