Sincronizzazione con il db

rated by 0 users
This post has 7 Replies | 3 Followers

Top 10 Partecipanti
Maschio
Post 268
Punteggio 4.922
petrux Posted: 06-30-2010 10.20
Ciao a tutti,

mi trovo nello scenario che ora descrivo.

class Item {
string Label { get; }
}
class Box {
IEnumerable Items { get; }
}

ora, ho una applicazione desktop (o un Service di windows, la cosa è
ancora da vedere, comunque è qualcosa che ha un ciclo di vita molto
lungo) che deve accedere e manipolare questi dati. Man mano che li
manipola, partono altri processi che possono andare a scrivere lo stesso
database. Ho quindi bisogno di sapere se una particolare istanza di Item
è stata modificata altrove.

Le possibili strategie che mi vengono in mente sono le seguenti:
1. usare una nuova sessione per ogni operazione che compio sugli Item
2. usare un modo di ri.sincronizzare le entities con i cambiamenti
occorsi sul db

La prima soluzione è di immediata implementazione. Tuttavia, volevo
sapere se esiste un qualche meccanismo per implementare anche la seconda
soluzione? Considerate che come OR/M uso NHibernate, ma non è detto che
non si debba passare a EF a berve. :-) Il db per ora è un SQL Server
Express (2008), ma anche qui non è detto che non si debba migrare a
Oracle/PostgreSQL.

Ciao e grazie,
petrux

--
  • | Punteggio Post: 20
Top 10 Partecipanti
Maschio
Post 244
Punteggio 3.403

Se non è pesante, la soluzione 1 è sicuramente quella che ti da meno problemi, io adotterei quella principalmente. Comunque in ogni caso io attiverei la concorrenza ottimistica, in questo modo nhibernate o EF ti tira un eccezione quando fai update su un oggetto che è stato modificato da qualcuno tra il momento in cui è stato letto ed il momento in cui lo salvi :)

Questo è indipendente dal db utilizzato, e supportato sia da EF sia da NHibernate.

Se non puoi ammettere questa situazione, un lock può essere la soluzione giusta, in alcuni casi un processo prende un oggetto, lo locka, lo lavora (per un tempo breve) per cui se qualcun altro ci accede rimane con il lock bloccato fino a che il primo non rilascia il lock. In questo caso le prestazioni si abbassano, ma puoi serializzare le operazioni ed evitare conflitti a priori.

alk.

  • | Punteggio Post: 35
Top 10 Partecipanti
Maschio
Post 67
Punteggio 1.440

quoto Alk: "scenario 1 tutta la vita" :-)

  • | Punteggio Post: 35
Top 10 Partecipanti
Maschio
Post 268
Punteggio 4.922
Ciao alk,

alkampfer wrote:
> Se non è pesante, la soluzione 1 è sicuramente quella che ti da meno
> problemi, io adotterei quella principalmente.

Ok, qui però si scatena un piccolo problema "di fondo" (collegato anche
all'altro thread, quello sulla responsabilità del data context). Faccio
un esempio.

//Entity
class Foo { ... }

//Astrazione per il data context;
interface IDataContext
{
void Add(object o);
void Delete(object o);
void Update(object o);
...blablabla...
}

//Business object
class MyService
{
protected IDataContext dc;

//costruttore;
public MyService(IDataContext dc) { this.dc = dc; }

//metodo;
public void DoSomething(Foo foo)
{
//blablabla
//qui, in teoria, qualcuno può aver cambiato
//il foo persistente sul db.
}
}

in sintesi: nel metodo DoSomething dovrei riuscire a ri-inizializzare la
sessione o a crearne una nuova.
La prima cosa non è una buona cosa :-) visto che permetterei ad un
componente qualsiasi di impattare in maniera così profonda qualcosa che
dovrebbe essere regolato da chi regola il ciclo di vita
dell'applicazione. La seconda cosa... dovrei iniettare un
IDataContextFactory invece che un IDataContext. Giusto?

Una soluzione alternativa sarebbe (andando a logica) questa:
- detachare 'foo' dalla sessione
- ricaricare il Foo con lo stesso ID (dovrebbe essere quello più aggiornato)
- verificare il cambiamento
- detachare il foo caricato in seconda battuta
- riattaccare la entity originale
- fare (eventualmente) l'update
E' possibile realizzarlo con NH/EF?

> Comunque in ogni caso io
> attiverei la concorrenza ottimistica, in questo modo nhibernate o EF ti
> tira un eccezione quando fai update su un oggetto che è stato modificato
> da qualcuno tra il momento in cui è stato letto ed il momento in cui lo
> salvi :)

Ci avevo pensato. In questo caso però, è possibile "refreshare" poi
l'oggetto in questione?

Ciao e grazie,
petrux

--
  • | Punteggio Post: 5
Top 10 Partecipanti
Maschio
Post 268
Punteggio 4.922
andysal wrote:
> quoto Alk: "scenario 1 tutta la vita" :-)

Leggi la risposta ad alk. :-)

Ciao,
petrux
--
  • | Punteggio Post: 20
Top 10 Partecipanti
Maschio
Post 244
Punteggio 3.403

Ho dato una sguardata veloce al codice, allora, solitamente la sessione viene gestita da "qualcuno". Il repository che ha i metodi add, remove, delete, query etc, quando deve fare un operazione chiede ad un SessionManager

GetSession

E stop. Nel web ci sarà un sessionmanager che gestisce una sessione per ogni richiesta, per un servizio ho intercettori che fanno una session per ogni chiamata al wcf, per mvvm hai un gestore che tiene la sessione con il view model etc etc.

Il bello di un ORM è questo, quando la sessione viene distrutta l'oggetto è automaticamente "Detatched", quando fai session.saveorUpdate(oggetto) lui automaticamente riattacca l'oggetto, controlla se è cambiato (se hai concorrenza ottimistica) etc etc etc. per cui diciamo che fai molta meno fatica del solito.

Il gestore di sessione è solitamente un robo che fa questo, quando gli vieen chiesta la sessione vede se ne è presente una nel suo contesto (e da Ioc come contesto puoi mettere httpcontext.current se sei nel web, remoting.callcontext, threadcontext, etc etc). Se no è presente ne crea una e la mette nel contesto, se è presente controlla se è chiusa, se è chiusa ne crea un altra come se non ci fosse, etc etc.

Questo perchè se fai un flush, e nh ti genera una eccezione, la sessione la devi scartare comunque, indpendntemetne dal suo ciclo di vita, non è più valida, non la puoi più usare, etc etc etc :)

 

alk.

  • | Punteggio Post: 5
Top 10 Partecipanti
Maschio
Post 268
Punteggio 4.922

Ciao Andrea,

 

Andrea Saltarello:

quoto Alk: "scenario 1 tutta la vita" :-)

 

Ho implementato lo scenario 1 e mi sono ritrovato con una bella "Illegal attempt to associate a collection with two open sessions".

 

Ok, ho sbagliato qualcosa ma... cosa?

;-)

 

Ciao e grazie,

Giulio

-- 

 

Top 10 Partecipanti
Maschio
Post 244
Punteggio 3.403

Hai un problema di gestione di sessione, questo errore significa che tu hai due sessioni vive e stai cercando di associare una collection con due sessioni conteporaneamente.

Questo tipo di errori dipende solitamente da una mancata chiusura delle sessioni e da un errato gestione del ciclo di vita della sessione stessa :)

Nhibernate profiler ti aiuta molto in questo caso. Verifica di non avere più sessioni aperte contemporanetamente per lo stesso flusso logico e che vengano sempre chiuse.

alk.

  • | Punteggio Post: 5
Pagina 1 di 1 (8 elementi) | RSS
Powered by Community Server (Commercial Edition), by Telligent Systems