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

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

Introduzione
Nel post [2] relativo ad NHibernate, avevamo visto come scrivere file di mapping per legare due classi con una relazione uno-a-molti. Nel caso specifico, lo riassumo in breve, avevamo una classe HockeyPlayer ed una classe Faults: ad un'istanza della prima, possono corrispondere più istanze della seconda. Senza andare troppo nel dettaglio, più che altro per non ripetere cose già dette, riporto qui sotto il mapping della classe HockeyPlayer:

<class name='HockeyPlayer' table='HockeyPlayers'>
    <
id name='ID' column='ID' type='Int32' length='4' unsaved-value="0">
      <generator 
class='identity' />
    <
/id>
    <property 
name='Name' type='String' column='Name' length='50'/>
    <property 
name='Height' type='Int32' column='Height' length='4'/>
    <property 
name='Weight' type='Int32' column='Weight' length='4'/>
    <property 
name='Number' type='Int32' column='Number' length='4'/>
    <bag 
name="Faults" cascade="all" lazy="false" inverse="true">
        <key 
column="IDPlayer" />
        <one-to-many 
class="Fault, HockeyObject" />
    <
/bag>
<
/class>

Detto questo, avevamo detto che anche la classe Faults deve essere mappata opportunamente. Quello che mi interessa far ricordare (e ricordare a me stesso) è che nella classe Fault deve esserci un riferimento all'istanza HockeyPlayer a cui appartiene il Fault stesso. Di conseguenza:

  <class name='Fault' table='Faults'>
    <
id name='ID' column='ID' type='Int32' length='4' unsaved-value="0">
      <generator 
class='identity' />
    <
/id>
    <property 
name='Reason' type='String' column='Reason' length='50'/>
    <property 
name='When' type='DateTime' column='[When]' length='4'/>
    <property 
name='FaultGravity' type='Int32' column='Gravity' length='4'/>
    <property 
name='FaultConsequence' type='Int32' column='Consequence' length='4'/>
    <many-to-one 
name="HockeyPlayer" column="IDPlayer"
        
class="HockeyPlayer, HockeyObject" cascade="none" />
  <
/class>

La cosa interessante è il parametro cascade contenuto nel tag many-to-one. Ricordiamoci sempre di metterlo a none: se non lo facciamo, succede una cosa strana ed un po' pericolosa. Se attraverso la classe DataProvider descritta qua, cancelliamo un oggetto Fault, in realtà cancelleremo anche il suo HockeyPlayer di appartenenza. Questo non va affatto bene: il fatto di voler cancellare un Fault non significa affatto che vogliamo cancellare anche il giocatore!  D'altra parte, se cancelliamo un oggetto Fault, NHibernate deve prima cancellare eventuali record in altre tabelle che lo usano come foreign-key, ed è proprio quello che accade!  Il tutto, teniamolo presente, in modo completamente trasparente rispetto al nostro data access layer: tutto è stabilito nei files di mapping, e non c'è nulla di cablato dentro il codice.

Ed una relazione uno-ad-uno?
Ho avuto un'altra necessità e per poterla descrivere qua, sono partito sempre dalla mia sample application. Ho uno HockeyPlayer e la proprietà Faults, relazionata uno-a-molti. Espandiamo lo scenario, aggiungendo la classe Squad esposta dalla classe HockeyPlayer. Ad ogni istanza di giocatore, esiste una ed al massima una istanza della squadra. La relazione questa volta è uno-a-uno. Come la si esprime nei files di mappings? Non è per nulla complicato, soprattutto alla luce di quello che abbiamo già visto precedentemente.

<one-to-one name="Squadron" class="Squad"
    
property-ref="HockeyPlayer" cascade="all" />

Il tag one-to-one deve essere aggiunto alla definizione della classe HockeyPlayer. Anche in questo caso, abbiamo la proprietà name che indica il nome della proprietà esposta dalla classe HockeyPlayer. La proprietà class indica il nome completo della classe. La proprietà property-ref indica il nome della proprietà sull'oggetto figlio che fa riferimento all'oggetto padre. Ovviamente, ho dovuto modificare l'implementazione della classe HockeyPlayer, aggiungendo la nuova proprietà:

// Field privato
private Squad squadron;

// Proprietà pubblica
public Squad Squadron
{
    
get return squadron; }
    
set { squadron = value; NotifyPropertyChanged("Squadron"); }
}

Come ultimissima cosa, vediamo come scrivere nel file Mappings.hbm.xml il mapping per la nuova classe Squad:

<class name='Squad' table='Squads'>
    <
id name='ID' column='ID' type='Int32' length='4' unsaved-value="0">
      <generator 
class='identity' />
    <
/id>
    <property 
name='Name' type='String' column='Name' length='50'/>
    <property 
name='City' type='String' column='City' length='50'/>
    <many-to-one 
name="HockeyPlayer" class="HockeyPlayer"
        
column="IDPlayer" unique="true" cascade="none" />
<
/class>

La classe Squad è molto semplice: espone due stringhe, una per il nome della squadra e l'altra per la città. La cosa interessante da far notare è che anche in questo caso abbiamo dovuto mettere il tag many-to-one per indicare il riferimento al padre: tra tutte le proprietà indicate in questo tag, la più interessante è sicuramente column, che indica qual'è il nome del campo che deve contenere il legame tra HockeyPlayer e la Squad corrispondente.

powered by IMHO 1.2

Print | posted on venerdì 23 giugno 2006 18:38 | Filed Under [ Sviluppo .NET ]

Comments have been closed on this topic.

Powered by:
Powered By Subtext Powered By ASP.NET