Questa guida è l'esatta (per quanto possibile) traduzione in italiano dell'omonima guida in lingua inglese presente sul sito ufficiale di NHibernate. Quick Start Guide
Cos'è NHibernate
NHibernate è una libreria per la persistenza di oggetti su database relazionali costruita sul framework .NET di Microsoft. E' un porting dell'eccellente strumento di persistenza per Java Hibernate.
NHibernate gestisce la persistenza di oggetti .NET da e verso il database relazionale sottostante. Invece di dover scrivere codice SQL per ottenere ed inviare gli oggetti al database, NHibernate si occupa di tutto questo al nostro posto. Il nostro codice si deve preoccupare solamente di gestire gli oggetti .NET, mentre NHibernate genera l'SQL e si assicura che gli oggetti finiscano nelle corrette tabelle e colonne del database.
Perchè questa guida?
Chiunque abbia qualche familiarità con Hibernate si noterà molte somiglianze con la guida A Hitchhiker's Guide to Hibernate di Glen Smith (ora è offline ). Il contenuto è basato su questa guida quindi tutti i meriti vanno accreditati a lui.
La documentazione di NHibernate non è nemmeno lontanamente paragonabile a quella di Hibernate. Tuttavia, i due progetti sono abbastanza simili da consentire di consultare anche la guida di Hibernate per capire come funziona NHibernate.
Questo documento è stato creato per consentire di iniziare con NHibernate più velocemente possibile. Ci occuperemo di come persistere un semplice oggetto in una tabella. Per esempi più complessi consultare i test di NUnit allegati alla distribuzione di NHibernate.
Per iniziare
E' necessaria una distribuzione di NHibernate. Scarica l'ultima versione, e decomprimi il contenuto in una cartella.
Il processo di sviluppo
NHibernate avrà in futuro alcuni strumenti per generare uno schema, generare classi dai file di mapping, e per aggiornare uno schema. Tuttavia, per questo esempio costruiremo tutto manualmente, dalla creazione della tabella alla codifica della classe .NET associata. Questi sono i passi che seguiremo:
- Creazione della tabella del database in cui persistere la classe .NET.
- Creazione della classe .NET che dovrà essere persistita.
- Creazione di un file di mapping, in modo da far sapere a NHibernate come persistere le proprietà della classe.
- Creazione di un file di configurazione per comunicare a NHibernate come connettersi al database.
Primo passo: Scrittura dell'SQL
L'esempio su cui lavoriamo è molto semplice. Supponiamo di dover sviluppare un semplice sistema di gestione degli utenti di un sito web. Useremo una tabella Users di questo tipo (dovrai avere già creato un database, nel mio caso il database si chiama NHibernate):
use NHibernate
go
CREATE TABLE users (
LogonID nvarchar(20) NOT NULL default '0',
Name nvarchar(40) default NULL,
Password nvarchar(20) default NULL,
EmailAddress nvarchar(40) default NULL,
LastLogon datetime default NULL,
PRIMARY KEY (LogonID)
)
go
Io sto usando MS SQL Server 2000, ma è possibile utilizzare un qualsiasi database per il quale esista un provider di dati .NET.
Abbiamo un tabella con LogonID, Nome, Password, Email e data dell'ultimo logon, è una situazione abbastanza standard. Il prossimo passo consiste nel creare una classe .NET per gestire un determinato User.
Secondo passo: Creazione della classe .NET
Quando carichiamo degli utenti in memoria, abbiamo bisogno di un oggetto per memorizzarli. NHibernate lavora tramite reflection sulle proprietà degli oggetti, quindi avremo bisogno di aggiungere proprietà alla classe che vogliamo persistere. Una semplice classe che puoi essere persistita tramite NHibernate può essere questa:
using System;
namespace NHibernate.Examples.QuickStart
{
public class User
{
private string id;
private string userName;
private string password;
private string emailAddress;
private DateTime lastLogon;
public User()
{
}
public string Id
{
get { return id; }
set { id = value; }
}
public string UserName
{
get { return userName; }
set { userName = value; }
}
public string Password
{
get { return password; }
set { password = value; }
}
public string EmailAddress
{
get { return emailAddress; }
set { emailAddress = value; }
}
public DateTime LastLogon
{
get { return lastLogon; }
set { lastLogon = value; }
}
}
}
Nel nostro esempio, abbiamo reso le proprietà ed il costruttore della classe public, ma non è un requisito essenziale; NHibernate può utilizzare proprietà di tipo public, protected, internal o anche private per persistere i nostri dati.
Terzo passo: Creazione del file di Mapping
Adesso abbiamo la nostra tabella SQL e la classe .NET che verrà mappata ad essa. A questo punto è necessario un modo per dire ad NHibernate come mappare tra la prima e la seconda. Questo si ottiene tramite un file di mapping. Il modo più pulito (e più mantenibile) è creare un file di mapping per ogni classe, e nominandolo TuoOggetto.hbm.xml (dove TuoOggetto è il nome della classe) e mettendolo nella stessa directory della classe, NHibernate rende le cose ancora più semplici. Di seguito è riportato un esempio di come il file di mapping User.hbm.xml può apparire:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
<class name="NHibernate.Examples.QuickStart.User, NHibernate.Examples" table="users">
<id name="Id" column="LogonId" type="String" length="20">
<generator class="assigned" />
</id>
<property name="UserName" column="Name" type="String" length="40"/>
<property name="Password" type="String" length="20"/>
<property name="EmailAddress" type="String" length="40"/>
<property name="LastLogon" type="DateTime"/>
</class>
</hibernate-mapping>
Diamo un'occhiata ad alcune righe interessanti del file. Il primo tag di interesse è il tag class. In questo modo mappiamo la classe (nome della classe, assembly) alla tabella Users del database. Questo è leggermente differente da come verebbe fatto con Hibernate. Dobbiamo dire ad NHibernate da dove caricare la classe. In questo caso stiamo caricando la classe NHibernate.Examples.QuickStart.User presente nell'assembly NHibernate.Examples.
NHibernate segue le stesse regole del Framework .NET per caricare i Tipi, quindi se hai alcuni dubbi su come specificare il Tipo dai un'occhiata all'SDK del Framework .NET.
Tralasciamo il tag id per il momento e parliamo dei tag property. Questo è il punto dove viene effettivamente eseguito il lavoro di mapping. L'attributo name è la proprietà nella nostra classe .NET, e l'attributo column è il nome del campo nella tabella del database.L'attributo type è facoltativo (NHibernate utilizzerà la reflection per trovarlo se non è specificato).
Torniamo al tag id. E' facile immaginare che questo tag abbia a che fare con la mappatura della chiave primaria della tabella. La sintassi del tag id è molto simile a quella dei tag property che abbiamo appena analizzato. Mappiamo la proprietà della classe (name) al campo della tabella nel database (column).
Il tag annidato generator specifica a NHibernate come generare la chiave primaria (NHibernate è felice di farlo per te, di qualsiasi tipo desideri, ma è necessario specificare come deve farlo). Nel nostro caso è di tipo assigned, il che significa che il nostro oggetto genererà autonomamente le proprie chiavi (l'oggetto User deve sempre avere uno UserID dopotutto). Se desideri che NHibernate generi le chiavi al posto tuo possono essere interessanti impostazioni di classe come uuid.hex e uuid.string (leggi il manuale per più informazioni).
Informazioni utili
Se stai utilizzando Visual Studio .NET per compilare il progetto assicurati di impostare la Build Action del file User.hbm.xml come Embedded Resource. Il file di mapping farà parte in questo modo dell' Assembly. L'importanza di questo dettaglio sarà evidente più tardi.
Informazioni utili
Se l'unica modifica che fai tra una compilazione e l'altra è ad un file di mapping, è necessario eseguire il Rebuild del progetto lo stesso, infatti Visual Studio .NET non effettua la ricompilazione se solo un file hbm.xml è stato modificato.
Quarto passo: Creazione di un file di configurazione per il database
Non abbiamo ancora detto ad NHibernate come trovare il nostro database. Il modo più diretto per farlo è inserire la configurazione di NHibernate all'interno del file di configurazione della nostra applicazione (app.config o web.config). Questo procedimento è equivalente all'utilizzo di un file Properties con Hibernate. Ecco come apparirà:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section
name="nhibernate"
type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
/>
</configSections>
<nhibernate>
<add
key="hibernate.connection.provider"
value="NHibernate.Connection.DriverConnectionProvider"
/>
<add
key="hibernate.dialect"
value="NHibernate.Dialect.MsSql2000Dialect"
/>
<add
key="hibernate.connection.driver_class"
value="NHibernate.Driver.SqlClientDriver"
/>
<add
key="hibernate.connection.connection_string"
value="Server=localhost;initial catalog=nhibernate;Integrated Security=SSPI"
/>
</nhibernate>
</configuration>
L'esempio precedente utilizza un driver SqlClient, si connette al database nhibernate su localhost ed utilizza Integrated Security. Ci sono altre proprietà che è possibile impostare per configurare l'accesso al database. Per maggiori informazioni consultare la documentazione
Nota: per una lista dei database supportati e relative configurazioni consultare NHibernate Supported Databases.
log4net
Nota che il file di configurazione precedente non contiene informazioni sulla configurazione di log4net. NHibernate utilizza log4net per loggare cosa succede internamente. In una applicazione in ambiente produttivo è raccomandabile configurare log4net e impostare NHibernate al livello di log appropriato per il relativo scenario. Configuring log4net Logging
Quinto passo: Iniziamo a fare magie con NHibernate
Il lavoro sporco adesso è finito. Se tutto è andato bene, dovremmo avere:
- User.cs - la classe in C# da persistere
- User.hbm.xml - il file di mapping di NHibernate per la classe
- app.config - il file di configurazione dell'applicazione, contenente le informazioni ADO.NET per NHibernate
- una tabella users nel database
Utilizzare NHibernate nel nostro codice sorgente è abbastanza intuitivo. I passi base sono:
- Aggiungi un riferimento a NHibernate.dll (si trova nella cartella 'bin' della release di NHibernate)
- Crea un oggetto di tipo Configuration
- Informa l'oggetto Configuration del tipo di oggetti che vuoi memorizzare
- Crea una sessione al database di tua scelta
- Effettua operazioni di Load, Save e Query sui tuoi oggetto
- Effettua il Flush() della Sessione per persistere i cambiamenti sul database
Diamo un'occhiata ad un pò di codice per chiarire il tutto.
Per non dover scrivere tutto il percorso delle classi che utilizziamo, inseriamo i seguenti using all'inizio della classe:
using NHibernate;
using NHibernate.Cfg;
Per prima cosa, creiamo un oggetto Configuration...
Questo oggetto conosce tutti i mapping che ci sono tra le classi .NET e le tabelle del database.
Configuration cfg = new Configuration();
cfg.AddAssembly("NHibernate.Examples");
Il nostro oggetto Configuration cerca all'interno dell'Assembly qualsiasi file con estensione .hbm.xml. Ci sono altri modi per aggiungere file di mapping, ma questo è probabilmente il più semplice.
Quindi, creiamo un oggetto Session...
L'oggetto ISession rappresenta una connessione al database sottostante, e ITransaction rappresenta una transazione managed di NHibernate.
ISessionFactory factory = cfg.BuildSessionFactory();
ISession session = factory.OpenSession();
ITransaction transaction = session.BeginTransaction();
Quindi, carichiamo, salviamo ed interroghiamo i nostri oggetti (Load, Save, Query)!
Adesso è sufficiente utilizzare i nostri oggetti .NET in modo nativo. Vogliamo memorizzare in nuovo User nel database? Ecco il codice:
User newUser = new User();
newUser.Id = "joe_cool";
newUser.UserName = "Joseph Cool";
newUser.Password = "abc123";
newUser.EmailAddress = "joe@cool.com";
newUser.LastLogon = DateTime.Now;
// Comunichiamo ad NHibernate che questo oggetto deve essere salvato
session.Save(newUser);
// Commit dei cambiamenti al database e chiusura della ISession
transaction.Commit();
session.Close();
Come è possibile vedere, la cosa bella di NHibernate è il basso overhead (la quantità di codice necessaria). Continuiamo ed interroghiamo in database per verificare che esista il nuovo record nel database. Per la maggior parte dobbiamo preoccupaci solamente dei business objects, ossia delle istanze delle nostre classi, e comunicare ad NHibernate quando abbiamo finito.
Supponiamo di voler recuperare un oggetto del quale conosciamo la user ID (es. durante un processo di login ad un sito). Dopo aver aperto la sessione è necessaria una sola riga di codice; passiamo la chiave e abbiamo fatto:
// apriamo un'altra sessione per recuperare lo user appena inserito
session = factory.OpenSession();
User joeCool = (User)session.Load(typeof(User), "joe_cool");
L'oggetto User è ancora "vivo", ossia è ancora connesso alla sessione corrente. Se cambiamo le sue proprietà esso verrà persistito con i cambiamenti al successivo Flush() della sessione.
// impostiamo la proprietà LastLogon dello User "joeCool"
joeCool.LastLogon = DateTime.Now;
// ripercuotiamo i cambiamenti dalla Session al Database
session.Flush();
Tutto quello che abbiamo dovuto fare perché NHibernate scrivesse i cambiamenti fatti è stato chiamare il metodo Flush() dell'oggetto Session. Continuiamo ed interroghiamo in database per verificare che la proprietà LastLogon è stata aggiornata per "joe_cool".
Ancora meglio, possiamo interrogare la tabella del database ed ottenere un oggetto System.Collection.IList di oggetti live. Proviamo a fare questo:
IList userList = session.CreateCriteria(typeof(User)).List();
foreach(User user in userList)
{
System.Diagnostics.Debug.WriteLine(user.Id + " ha effettuato l'ultimo login il " + user.LastLogon);
}
Questa query ritorna l'intera tabella. Tipicamente si vuole molto più controllo sui risultati - ad esempio vogliamo ottenere la lista di Users che hanno fatto il login dopo il 14 Marzo 2004, alle 10:00 PM - allora scriviamo il codice seguente:
IList recentUsers = session.CreateCriteria(typeof(User))
.Add(Expression.Expression.Gt("LastLogon", new DateTime(2004, 03, 14, 22, 0, 0)))
.List();
foreach(User user in recentUsers)
{
System.Diagnostics.Debug.WriteLine(user.Id + " ha effettuato l'ultimo login il " + user.LastLogon);
}
Esiste una grande varietà di opzioni per interrogazioni sul database nella documentazione, ma questo ci dà un'idea della potenza offerta da NHibernate.
... Infine chiudiamo la nostra sessione (Close()). Questo libererà la connessione ADO.NEt che NHibernate sta utilizzando.
// diciamo ad NHibernate di chiudere la Sessione
session.Close();
Ed ecco fatto...
Abbiamo creato degli oggetto, li abbiamo persistiti, ed ottenuti dal database (attraverso query con Criteria e con ricerca per chiave). Dobbiamo essere contenti di quello che abbiamo fatto !
Ora che abbiamo preso contatto con NHibernate, è il momento di cominciare a guardare la documentazione di NHibernate, o quella di Hibernate 2.03 per quello che riguarda le parti in cui quella di NHibernate è ancora incompleta. C'è una grande quantità di informazioni da esplorare, come ad esempio la gestione di relazioni uno-a-molti, la persistenza di collezioni ordinate e annidate, tuning delle prestazioni e tanto altro.
Buon divertimento con NHibernate!
powered by IMHO 1.3