Technology Experience

Contenuti gestiti da Igor Damiani
posts - 949, comments - 2741, trackbacks - 15120

My Links

News

  • Questo blog si propone di raccogliere riflessioni, teoriche e pratiche, su tutto quello che riguarda il world-computing che mi sta attorno: programmazione in .NET, software attuale e futuro, notizie provenienti dal web, tecnologia in generale, open-source.

    L'idea è quella di lasciare una sorta di patrimonio personale, una raccolta di idee che un giorno potrebbe farmi sorridere, al pensiero di dov'ero e cosa stavo facendo.

    10/05/2005,
    Milano

Archives

Post Categories

Generale

[1] NHibernate: un caso tratto da un'applicazione reale

Sono impazzito molto nei giorni scorsi nel tentativo di sfruttare NHibernate per persistere business object del domain model di un'applicazione reale che sto sviluppando. Finchè si tratta di oggetti semplici, nessun problema, ma nel mio caso avevo a che fare con due oggetti relazionati uno-a-molti. Ieri sera ho risolto il mio problema, ma ho voluto replicare lo stesso scenario in una sample application di cui ho già parlato in passato, per descrivere meglio il mio dilemma e per spiegare come l'ho risolto.

Le classi coinvolte: HockeyPlayer e Fault
La classe HockeyPlayer rappresenta un giocatore di hockey, con tutte le proprietà che possono interessare. La proprietà ID (di tipo int) è la mia chiave. Poi ho Name, Height, Weight, Number e Faults. Quest'ultima rappresenta l'elenco dei falli che il giocatore ha subìto durante una partita. Inizialmente, la proprietà Faults era di tipo FaultsCollection, che a sua volta ereditava direttamente da BindingList<Fault>. Tutto abbastanza semplice, tutto sommato. Qual'era il mio dilemma?

Volevo usare NHibernate per salvare su database ogni istanza di HockeyPlayer: d'altronde NHibernate serve proprio per questo. Una volta definite le classi, è sufficiente creare il file di mapping corretto, e scrivere qualche linea di codice C# per ottenere quello che vogliamo. Fosse facile!  A parte scherzi, come potete immaginare la questione è tutta qui, ma non solo. Voglio annotare alcuni punti importanti che a me erano sfuggiti, magari a chi è un po' più veterano di NHibernate possono sembrare banalità.

  1. NHibernate non può persistere oggetti di tipo BindingList. Per questo motivo, nella mia sample application ho eliminato la classe FaultsCollection. La proprietà Faults di HockeyPlayer è di tipo IList, che al contrario uno di quei tipi con cui NHibernate lavora nativamente. 
  2. Ogni istanza della classe Fault deve avere un riferimento al suo HockeyPlayer, in modo che NHibernate possa gestire correttamente la foreign-key sulla tabella.

Detto questo, andiamo avanti. La classe HockeyPlayer si presenta essenzialmente così:

public class HockeyPlayer : INotifyPropertyChanged
{
    
#region Field
    private int 
id;
    
private string name;
    
private int height;
    
private int weight;
    
private int number;
    
private IList faults;
    
#endregion
}

Per brevità, ho riportato solamente i field privati. Le proprietà pubbliche non fanno nulla di particolare: hanno solamente la chiamata a NotifyPropertyChanged per il databinding. Notare che, come dicevo prima, l'elenco dei falli di ciascun giocatore è esposto tramite IList. I field privati della classe Fault sono i seguenti:

public class Fault
{
    
#region Field
    private int 
_id;
    
private string _reason;
    
private DateTime _when;
    
private FaultGravityEnum _gravity;
    
private FaultConsequenceEnum _consequence;
    
private HockeyPlayer _hockeyPlayer;
    
#endregion
}

Anche qui, ad ogni field corrisponde evidentemente una proprietà pubblica. Notare la presenza della proprietà HockeyPlayer, che è un riferimento allo HockeyPlayer a cui è associato il Fault. FaultGravityEnum e FaultConsequenceEnum sono due semplici enum che ho definito per comodità.

Un tipico uso di questo domain model
Detto questo, io posso scrivere codice C# per istanziare questi oggetti. Ad esempio:

Fault ft = new Fault("Push & Pop! :-)", DateTime.Now);
ft.FaultConsequence = FaultConsequenceEnum.Penalty;
ft.FaultGravity = FaultGravityEnum.Low;

HockeyPlayer player = 
new HockeyPlayer("Mike Modano", 183, 100, 28);
ft.HockeyPlayer = player;
player.Faults.Add(ft);

Qui creo un oggetto Fault, con dei valori a caso. Successivamente creo uno HockeyPlayer ed associo il Fault creato prima, ricordandomi di passare il riferimento all'oggetto padre. Come posso persistere questo oggetto? Come posso utilizzare NHibernate per dire: " Salvami l'oggetto player!". Trattandosi di due business object legati da una relazione uno-a-molti, così sarà evidentemente anche su database: avrò una tabella HockeyPlayers per mantenere tutte le istanza dei giocatori, ed una tabella Faults che conterrà i Faults di ciascun giocatore. In questa tabella, avrò un campo IDHockeyPlayer che sarà la foreign-key per mantenere il legame.

Dopo questa prima richiesta (salvataggio dell'oggetto), ne seguono altre due: quando recupero l'oggetto HockeyPlayer salvato, mi verranno recuperati anche i Fault ad esso associati? Se cancello l'oggetto, mi cancella anche i Faults ad esso legati? Quest'ultima, in particolare, è obbligatoria, altrimenti il database mi bloccherebbe l'operazione, perchè avrei una violazione di chiave.

Alla prossima...
Adesso non ho tempo, il lavoro chiama, ma ho tutto il materiale qui pronto per essere pubblicato. Spero di riuscire a farlo quanto prima. Forse sto buttando via del tempo, ma credo che sia utile, perchè troppe cose vengono date per scontate. Ho perso tempo io, ma se posso evitarlo a voi, tanto meglio!

powered by IMHO 1.2

Print | posted on martedì 13 giugno 2006 16:51 | Filed Under [ Sviluppo .NET ]

Feedback

Gravatar

# re: [1] NHibernate: un caso tratto da un'applicazione reale

Da ciò che hai scritto mi pare di aver capito ke hai cambiato il tipo di una child collection per poterla utilizzare con NHibernate....non mi sembra una cosa bella da fare. Mi spiego meglio, o per lo meno ti espongo il mio punto di vista. Secondo me modificare il business model per poter utilizzare un tool di sviluppo mi pare una una cosa pericolosa in quanto rischi farti condizionare da un tool di sviluppo (che dovrebbe essere di solo supporto e pertanto trasparente per la realizzazione dell'architettura). A tendere potresti ritrovarti in situazioni spiacevoli a causa di soluzioni simili. Nell'esempio concreto mi pare che la sola interfaccia IList non sia la cosa migliore per il tipo di informazione che la classe Faults deve gestire. Un'altro picco lspunto di riflessione dervia da un'altro constraint che NHibernate ti ha imposto: Avere un riferimento all'oggetto padre nella classe Fault. In caso di serializzazione avresti appena creato una circular reference....e questo non è bene ;). PEr quest'ultimo caso la soluzione potrebbe essere quella di usare solo la primary key di hockeyPlayer invece dell'intero oggetto in modo da non avere problemi in futuro (ad esempio se rendessi remotable il tuoi BO).
Per i lproblema di BindingList-NHibernate secondo me sarebbe da sviscerare meglio prima di lanciarsi in soluzioni periocolose (senza voler offendere, però la tua non mi pare una soluzione sembra + un workaround).

Il tutto ovviamente IMHO. Se ti va di approfondire ne sarei felice.



13/06/2006 18:39 | Alessandro Di Noia
Gravatar

# re: Uso di IList...a prescindere da NHibernate

14/06/2006 19:22 | jankyBlog
Gravatar

# [1] Il ritorno dello HockeyPlayer (data-binding con WPF)

[1] Il ritorno dello HockeyPlayer (data-binding con WPF)
17/05/2007 15:11 | Technology Experience (Reborn)
Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET