Ereditarietà e polimorfismo sono due caratteristiche 
della programmazione OO estremamente potenti, che possono essere sfruttate anche 
nella costruzione di domini complessi. La persistenza su un DBMS di queste 
strutture, però, pone dei problemi, in quanto non sono direttamente mappabili su 
un modello ER.
Supponiamo di dover persistere su DBMS il seguente dominio:

Come realizzare lo schema del DB? Beh, una trattazione completa 
dell'argomento è decisamente eccessiva, per cui si rimanda ad altre fonti, a noi 
basta semplicemente sapere che le scelte più usate ricadono tra:
  - Table per class hierarchy, in cui una sola tabella contiene una colonna per ogni 
  attributo di qualsiasi classe della gerarchia, e quindi è capace di contenere 
  tutta la gerarchia di oggetti; i diversi tipi sono distinti dal valore di una 
  particolare colonna, chiamata discriminatore;
  
 - Table per subclass, in cui si crea una tabella per ogni oggetto di qualsiasi 
  livello, le tabelle degli oggetti figlio contengono una FK verso le tabelle 
  relative agli oggetti padre;
  
 - Table per concrete class, in cui si crea una tabella per 
  ogni oggetto figlio, contenente tutte le proprietà dello stesso e dell'oggetto 
  padre.
 
Il terzo caso pone anche alcune problematiche nel caso in cui esistano delle 
reference (da tradurre in relazioni su DB) tra altre entity e un oggetto padre 
(es. Persona -> Veicolo posseduto: sulla tabella Persone che codice metto? 
ID_Motociclo? ID_Automobile? entrambi?); inoltre, non è direttamente mappabile 
in NHibernate (lo è su Hibernate per Java dalla versione 3 in poi, credo) e per 
questa ragione lo trascureremo. Ci concentreremo, allora, sui primi due 
casi.
Table per class hierarchy
In questo caso è necessario utilizzare nel file di mapping il nodo 
Discriminator, che accetta un attributo Column per indicare il nome 
della colonna utilizzata per differenziare i vari tipi. La classe padre (e le 
classi figlio, mappate tramite l'elemento Subclass), presentano un 
attributo che indica il valore del discriminatore associato al tipo stesso:
<class name="NHSubclassTest.Veicolo, NHSubclassTest" 
    table="CLASS_Veicoli">
    <!-- ... -->
    <discriminator column="TipoVeicolo" />
    <!-- properties di Veicolo -->
    <subclass name="NHSubclassTest.Automobile, NHSubclassTest" 
        discriminator-value="A">
        <!-- properties di Automobile -->
    </subclass>
    <subclass name="NHSubclassTest.Motociclo, NHSubclassTest" 
        discriminator-value="M">
        <!-- properties di Motociclo -->
    </subclass>
</class>
Come si può notare, ovviamente, il nome della tabella è specificato 
solo nella classe padre. Proviamo ad eseguire del codice e vediamo come reagisce 
NHibernate. Supponiamo di voler memorizzare una entity:
using (ISession session = SessionHelper.GetSession())
{
    Automobile auto = new Automobile();
    // valorizzo le properties di auto
    session.SaveOrUpdate(auto);
    session.Flush();
}
Come è lecito aspettarsi, NH produrrà una query di inserimento sul DB con il 
valore del discriminator impostato ad "A", dato che stiamo persistendo 
un'istanza del tipo Automobile, e con i campi specifici di Motociclo tutti pari 
a NULL:
exec sp_executesql N'INSERT INTO CLASS_Veicoli (Furgonato, NumeroPorte, Modello, 
Marca, Cilindrata, TipoVeicolo, ID_Veicolo) VALUES (@p0, @p1, @p2, @p3, @p4, ''A'', 
@p5)',N'@p0 bit,@p1 int,@p2 nvarchar(4000),@p3 nvarchar(4000),@p4 int,@p5 
uniqueidentifier',@p0=1,@p1=3,@p2=N'Punto',@p3=N'Fiat',@p4=1600,
@p5='D96E2365-6E84-4E75-9712-003E5EEADA9C'
Una caratteristica interessante è che possiamo caricare con una Get un 
generico oggetto di tipo Veicolo, penserà poi NHibernate a costruire, a 
seconda del discriminator, il tipo concreto corretto. Stesso dicasi se vogliamo 
recuperare un elenco di veicoli presenti nel database: il metodo ICriteria.List 
restituirà una IList<Veicolo> con all'interno i tipi concreti memorizzati 
nel database:
using (ISession session = SessionHelper.GetSession())
{
    // recupero un elenco di veicoli
    IList<Veicolo> lista = session
        .CreateCriteria(typeof(Veicolo))
        .List<Veicolo>();
    foreach (Veicolo v in lista)
    {
        Console.WriteLine("Veicolo n.{0}, tipo {1}", 
            lista.IndexOf(v), v.GetType().Name);
    }    
}
using (ISession session = SessionHelper.GetSession())
{
    // corretto caricamento delle istanze
    // uso una session differente per evitare il caching di primo livello
    Veicolo veicolo = session.Get<Veicolo>(id);
    Debug.Assert(veicolo != null, 
        "Grazie al polimorfismo, recupero una generica istanza di veicolo");
}
Lo svantaggio di questo approccio è quello di dover creare una tabella 
su DB per sua natura un po' "sporca", visto che effettivamente memorizza 
informazioni eterogenee che richiederanno, di volta in volta, di valorizzare 
alcune colonne piuttosto che altre.
Table per subclass
Per utilizzare il secondo approccio, è necessario modificare leggermente il 
mapping del dominio, utilizzando l'elemento joined-subclass in luogo 
del precedente:
<class name="NHSubclassTest.Veicolo, NHSubclassTest" 
    table="SUBCLASS_Veicoli">
    <!-- proprietà di Veicolo -->
    <joined-subclass name="NHSubclassTest.Automobile, NHSubclassTest" 
        table="SUBCLASS_Automobili">
        <key column="ID_Automobile" />
        <property name="Furgonato" />
        <property name="NumeroPorte" />
    </joined-subclass>
    <joined-subclass name="NHSubclassTest.Motociclo, NHSubclassTest" 
        table="SUBCLASS_Motocicli">
        <key column="ID_Motociclo" />
        <property name="Bauletto" />
        <property name="TipoForcella" />
    </joined-subclass>
</class>
NHibernate persisterà le informazioni separatamente, inserendo i 
valori relativi alle proprietà di ogni classe della gerarchia all'interno della 
tabella assegnata ed avendo cura che le chiavi primarie coincidano. Lo snippet 
di codice di creazione di un automobile esposto in precedenza, questa volta 
produce le seguenti query su DB:
exec sp_executesql N'INSERT INTO SUBCLASS_Veicoli ....'
exec sp_executesql N'INSERT INTO SUBCLASS_Automobili .....'
Come si può notare, questa volta la memorizzazione (e lo 
stesso dicasi per l'eliminazione e per le 
modifiche che coinvolgono proprietà di entrambi i livelli) 
richiede l'esecuzione di due query su database, numero che 
aumenta di pari passo con la profondità della gerarchia. 
L'esecuzione di una Get produce invece un output differente, a seconda che si 
tratti della ricerca di una classe concreta o di una astratta. Se infatti 
richiediamo una istanza di Motociclo, infatti, NHibernate sa già che per 
recuperare tutte le informazioni dovrà effettuare un join tra la tabella dei 
Veicoli e quella dei Motocicli; quindi, lo snippet seguente
using (ISession session = SessionHelper.GetSession())
{
    Motociclo moto = session.Get<Motociclo>(myId);    
}