Cambiare l'entity key di una entità [idea perversa inside]

rated by 0 users
This post has 10 Replies | 2 Followers

Top 10 Partecipanti
Maschio
Post 268
Punteggio 4.907
petrux Posted: 02-26-2010 15.37
Ciao a tutti,

prendendo come scenario una applicazione che usa NHibernate come ORM,
supponiamo di avere questo:

ISession session = ..;
Foo foo = new Foo();
Object key = session.Save(foo);

A questo punto, se non ho capito male, NHibernate tramite il mapping
capisce che la chiave primaria del mio oggetto foo è la sua property
"Id", nel momento in cui l'entità persiste io mi ritrovo:

Assert.AreEqual(foo.Id, key);

Tutto ciò è molto fiqo.
A questo punto però mi chiedo:
- è quindi necessario che la property che sia mappata sulla chiave
primaria abbia un setter pubblico?
- oppure è lecito pensare che dopo che la sessione viene resa
persistente l'istanza 'foo' non sia più valida e debba quindi ri-caricarla?
- in tal caso, come faccio nel mio caso in cui non sto lavorando su una
classica applicazione LOB/Enterprise, ma su una specie di CAD in cui le
sessioni possono durare anche *giorni* :-) e in cui la chiave primaria
di ogni entità deve essere devinita alla creazione (e non soltanto al
momento della sincronizzazione della persistenza)?
- qualora sia semplicemente vera la prima ipotesi (ovvero quella del
setter pubblico), fare qualcosa tipo:

foo.Id = new object();

non è impossibile. Mi chiedo: è semplicemente una cosa *molto* stupida,
benché possibile?

Ciao e grazie,
Giulio

--
  • | Punteggio Post: 20
Top 10 Partecipanti
Post 143
Punteggio 2.560
Ciao Giulio,

You wrote on 26/02/2010 :
> A questo punto però mi chiedo:
> - è quindi necessario che la property che sia mappata sulla chiave
> primaria abbia un setter pubblico?

no, basta che sia protected e NH via dynamic proxy all'atto dalla
creazione della entity sincronizza la key de db con quella della
entity.

> - oppure è lecito pensare che dopo che la sessione viene resa
> persistente l'istanza 'foo' non sia più valida e debba quindi ri-caricarla?

resta validissimissima :-)

> - in tal caso, come faccio nel mio caso in cui non sto lavorando su una
> classica applicazione LOB/Enterprise, ma su una specie di CAD in cui le
> sessioni possono durare anche *giorni* :-) e in cui la chiave primaria
> di ogni entità deve essere devinita alla creazione (e non soltanto al
> momento della sincronizzazione della persistenza)?
> - qualora sia semplicemente vera la prima ipotesi (ovvero quella del
> setter pubblico), fare qualcosa tipo:

dipende molto dal contesto ma perch� non eneri tu la chiave
applicativamente? nel mapping poi spieghi ad NH queli sono le logiche
per cui capire se una entity e nuova (insert) o modificata (update),
tipicamente se lo scenario � disconnesso non ti puoi fidare del "db"
perch� non � detto che sia online quindi cme key uso un Guid che genero
applicativamente qando creo l'istanza dell'entit�:

class MyEntity
{
public virtual Guid Key{ get; protected set; }

public MyEntity()
{
this.Key = Guid.NewGuid();
}
}

> Ciao e grazie,
> Giulio
>
> --

..m

--
Mauro Servienti
{C67C0157-5D98-4733-A75E-93CAEE4BADC8}
Microsoft MVP - Visual C# / MCP
http://mvp.support.microsoft.com
http://blogs.ugidotnet.org/topics
whynot [ at ] topics [ dot ] it
  • | Punteggio Post: 20
Top 10 Partecipanti
Maschio
Post 243
Punteggio 3.383

Propendo anche io per le chiavi Guid, che hanno un ulteriore vantaggio, durante la Save, nhibernate non deve per forza fare l'insert fisico dell'oggetto nella tabella per prendere l'id. In questo caso puoi lasciare comunque generare a lui il guid, cosi se hai un guid.null sai che non è mai stato inserito in sessione, e puio usare il saveorUpdate. Altrimenti come dice mauro lo metti tu a mano, ma poi devi tenere traccia se l'oggetto è persistente o meno, per capire se chiamare save o update.

In generale tutte le identità autogenerate dal db possono in generale causare problemi.

Cmq io eviterei sessioni che durano *giorni*, puoi avere un impatto sulla memoria disarmante, visto che ogni ISession di nhibernate si tiene in memoria tutti gli oggetti che ha salvato/caricato/reidtratato.

alk.

 

  • | Punteggio Post: 20
Top 10 Partecipanti
Maschio
Post 268
Punteggio 4.907
Ciao alk,

alkampfer wrote:
> In generale tutte le identità autogenerate dal db possono in generale
> causare problemi.

E perchè? :-)

> Cmq io eviterei sessioni che durano *giorni*, puoi avere un impatto
> sulla memoria disarmante, visto che ogni ISession di nhibernate si tiene
> in memoria tutti gli oggetti che ha salvato/caricato/reidtratato.

Si, va be' ma... mica lo decido io.
Se hai mai lavorato con AutoCAD, Simulink o robaccia del genere, capisci
anche che non è che posso salvare a ogni modifica. Se poi ci hai
lavorato e sai come sono fatti "dentro"... ancora meglio: vuota il
sacco! :-D

Ciao e grazie,
Giulio
--
  • | Punteggio Post: 20
Top 10 Partecipanti
Maschio
Post 243
Punteggio 3.383

Chiavi autogenerate forzano l'ORM a fare insert immediatamente appena chiami il Save, questo ti può dare problemi se ad esempoi hai scelto il FlushMode=Never, perchè in realtà quando inserisci il flush lo fa subito. Un esempio concreto

Supponiamo che in una app web hai l'utente che naviga un wizard di X pagine, in ogniuna mette dei dati, alla fine decide se commitare tutto o no. Un possibile approccio è quello di dire, ad ogni step io prendo gli oggetti, li salvo in session ma con flushmode = never alla fine decido se fare il flush. Purtroppo non funziona. (Cmq ci sono modi molto migliori di fare questo senza toccare il flush mode :) Era solo un piccolo esempio. )

Un altro problema è, supponiamo di ammettere che il db possa essere disconnesso, ad esempio ho un tablet con cui l'utente viaggia in giro per un capannone con la wirless, avere la possibilità di dire, io intanto le entità le salvo, ma poi il flush lo faccio solo quando ho la rete e sono convinto che tutto vada può essere un vantaggio.

Per il discorso autocad il fatto è questo, una session di nhibernte tiene tutti gli oggetti in memoria nella sua Identity Map Interna, per questa ragione non è sempre consigliabile tenere la sessione viva per moltissimo tempo, devi fare una stima. Se vuoi tenere la sessione sempre attiva allora dovresti magari fare evict degli oggetti che non usi più. Se invece sai che non hai problemi di memoria puoi tenere sempre la stessa ma fai attenzione che

1) Se in una transazione per qualche ragione fai il rollback la sessione va disposata, non la puoi più usare.

2) Se in una operazione di salvataggio/inserimento o flush nhibernate fa eccezione, anche se tu la gestisci la sessione va disposata :)

alk.

  • | Punteggio Post: 20
Top 10 Partecipanti
Maschio
Post 268
Punteggio 4.907

Ciao alk,

Gian Maria Ricci:

Per il discorso autocad il fatto è questo, una session di nhibernte tiene tutti gli oggetti in memoria nella sua Identity Map Interna, per questa ragione non è sempre consigliabile tenere la sessione viva per moltissimo tempo, devi fare una stima. Se vuoi tenere la sessione sempre attiva allora dovresti magari fare evict degli oggetti che non usi più. Se invece sai che non hai problemi di memoria puoi tenere sempre la stessa ma fai attenzione che

1) Se in una transazione per qualche ragione fai il rollback la sessione va disposata, non la puoi più usare.

2) Se in una operazione di salvataggio/inserimento o flush nhibernate fa eccezione, anche se tu la gestisci la sessione va disposata :)

 

Mumble mumble... facciamo un discorso "generale" (ma sempre aderente al mio caso). So che non ho problemi di memoria, quindi posso tranquillamente tenere in memoria tutti gli oggetti. Il problema dispose/salvataggio (insomma, del Dispose della session) non mi spaventa, nel senso che lo scenario non presenta troppi problemi da questo punto di vista. Il problema principale però sta nel fatto che:

- è difficile modellare il mio dominio in maniera che possa essere simile a una descrizione secondo il modello E-R

- la persistenza non è su un DB

- la chiave va generata alla *creazione* dell'entità e non al suo salvataggio e deve essere valida anche se l'entità è transiente

Quindi alla fine, mutuando un po' qui e un po' lì, dando uno sguardo a NHibernate e seguento attentamente i vostri consigli sono riuscito a impostare qualcosa di decente. Ora, devo capire bene il discorso dynamic proxy (qualche link?) ma credo di essere sulla buona strada.

Ciao e grazie,

Giulio

 

--

 

  • | Punteggio Post: 20
Top 10 Partecipanti
Maschio
Post 243
Punteggio 3.383

In questo caso la chiave guid, generata da te è la cosa migliore, devi solo capire quali oggetti sono stati salvati e quali no per sapere se chiamare save o Update.

Per il discorso dynamic proxy ti consiglio questo link http://kozmic.pl/archive/2009/04/27/castle-dynamic-proxy-tutorial.aspx si tratta di una libreria per la generazione dinamica di codice in grado di generare proxy per le tue interfacce, viene usata da nhibernate per fare il lazy load, ma considera che non sei bloccato solo ad usare castle, ma puoi usare anche altre librerie perchè dalle ultimke versioni di nhibernate è configurabile.

alk.

  • | Punteggio Post: 20
Top 10 Partecipanti
Maschio
Post 268
Punteggio 4.907
Ciao alk,

alkampfer wrote:
> In questo caso la chiave guid, generata da te è la cosa migliore, devi
> solo capire quali oggetti sono stati salvati e quali no per sapere se
> chiamare save o Update.

Uhm... e se non avessi la persistenza su un db?

> Per il discorso dynamic proxy ti consiglio questo link
> http://kozmic.pl/archive/2009/04/27/castle-dynamic-proxy-tutorial.aspx
> si
> tratta di una libreria per la generazione dinamica di codice in grado di
> generare proxy per le tue interfacce, viene usata da nhibernate per fare
> il lazy load, ma considera che non sei bloccato solo ad usare castle, ma
> puoi usare anche altre librerie perchè dalle ultimke versioni di
> nhibernate è configurabile.

Ok, gli do uno sguardo ASAP.
Anche se non mi serve nell'immediato, di sicuro "fa cultura". :-)

Ciao e grazie,
Giulio
--
  • | Punteggio Post: 20
Top 10 Partecipanti
Maschio
Post 243
Punteggio 3.383

petrux:
alkampfer wrote:
> In questo caso la chiave guid, generata da te è la cosa migliore, devi
> solo capire quali oggetti sono stati salvati e quali no per sapere se
> chiamare save o Update.

Uhm... e se non avessi la persistenza su un db?

Se non hai la persistenza su db, non hai problemi, nel senso che quegli oggetti non li passi a nhibernate e magari li salvi da un'altra parte con altre tecniche etc etc. Alla fine se un oggetto non viene persistito non ha nemmeno molto senso che abbia un campo Id, la sua identità può essere garantita dal framework.

Alk.

  • | Punteggio Post: 20
Top 10 Partecipanti
Maschio
Post 268
Punteggio 4.907
Ciao alk,

alkampfer wrote:
> Alla fine se un oggetto non viene persistito
> non ha nemmeno molto senso che abbia un campo Id, la sua identità può
> essere garantita dal framework.

E' un presupposto decisamente pretenzioso :-)
Nel mio caso - ad esempio - ad ogni oggetto va assegnato un ID univoco
che deve venire serializzato e al successivo editing deve rimanere lo
stesso. Quindi un modo per gestire 'sta cosa, in qualche modo, me lo
dovrò pure inventare. :-)

Ciao,
Giulio
--
  • | Punteggio Post: 20
Top 10 Partecipanti
Maschio
Post 243
Punteggio 3.383

Puoi quindi lavorare con id assegnati dal software e usare i guid per non avere problemi. A quel punto gli oggetti che vanno nel db non hanno problemi, gli metti l'id assigned, quelli che non vuoi mettere nel db e vuoi salvare da altre parti non hai comunque porblemi perchè serializzando e deserializzando ti ritrovi l'id li, probabilmente è la soluzione più semplice :)

 

alk.

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