The official Fatica Labs Blog! RSS 2.0
# Friday, September 03, 2010

Meglio, più in generale, non funziona più l’intellisense per qualsiasi documento XML per cui abbiamo uno ( o più.. ) XSD. Questo accade perchè Visual Studio trova più sorgenti per lo schema dichiarato nell’ XML, nel caso NHibernate abbiamo la seguente dichiarazione in testa:

<?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="....." namespace="....." >

Se abbiamo nella solution, o nella directory %Program Files%/Microsoft Visual Studio XXX/Xml/Schemas  uno o più file che definiscono lo stesso namespace, in questo caso

<xs:schema targetNamespace="urn:nhibernate-mapping-2.2" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="urn:nhibernate-mapping-2.2" elementFormDefault="qualified" attributeFormDefault="unqualified">

Visual Studio trova un ambiguità per cui smette di fornire l’intellisense. La situazione si può risolvere facilmente senza disperare:

Basta cliccare sul documento XML da visual studio e dalla finestra proprietà editare la voce Schemas come mostrato qui sotto:

xmlschemas

Così facendo si apre una finestra in cui è possibile abilitare/disabilitare gli schema che visual studio intende usare:

xmlschema2

Deselezionando uno degli schemi ambigui tutto torna a funzionare. Ovviamente questo funziona per qualsiasi ambiguità di schema, non solo per NHibernate.

Friday, September 03, 2010 10:28:31 AM (GMT Daylight Time, UTC+01:00)  #    Comments [3] - Trackback
NHibernate | Programmin
# Wednesday, September 01, 2010
continua da Parte1: Cosa ci serve

In questa parte costruiamo un progetto con NHibernate che ci consentirà di persistere una prima entità. In effetti la parte OR/M sarà tenuta il più semplice possibile, niente reference o collezioni o componenti: l’obiettivo è creare uno scheletro funzionante e testabile. Ovviamente tutto quanto detto servirà da spunto, alcune cose potranno sembrare ovvie, altre meno, fate come credete meglio, ma poichè questo è un corso “da zero” voglio soffermarmi su tutti i punti.

Decidiamo di mettere le entitità in una Class Library ( dll ). Questa è una scelta che probabilmente sarà conveniente fare anche per una soluzione vera da mandare in produzione. Creiamo quindi una nuova solution con Visual Studio. Distinguiamo il nome della soluzione con NHFromScratch.All, ed aggiungiamo all interno un nuovo progetto di tipo class library, che andiamo a chiamare NHFromScratch.Entities.

t1

All’ interno della cartella radice della solution, creiamo una sottocartella “Lib”, atta a contenere le dipendenze della soluzione ( NHibernate e non ), ad esempio in aggiunta alle dipendenze di NH vedete la nunit.framework.dll, dipendenza che ci servirà a breve quando vorremo testare le nostre entità.

t2

Bene, il passo successivo è creare il mapping per la prima ed unica entità che vogliamo gestire. Ci sono una moltitudine di strategie per creare un mapping per NH, quella che presento qua è una soluzione “plain vanilla”, senza nessun fronzolo e a costo zero: con la pratica ognuno sceglie il metodo che meglio crede, ma per imparare è mia opinione che scrivere il file XML sia di aiuto. Aggiungiamo quindi una sottocartella “Mapping” nella class library appena creata, e in questo folder creiamo un nuovo file con il nome della entità ( Customer nel nostro caso ) con l’estensione .hbm.xml. Se abbiamo abilitato l’intellisense, come fortemente consigliato nella parte 1 l’unico tag che dobbiamo ricordare a memoria è <hibernate-mapping>, tutti gli altri saranno esposti via intellisense dopo che il namespace sarà correttamente specificato, come mostrato qui sotto:

 t4

Cosa importantissima da ricordare, ricordiamo di impostare “Embedded Resource” come build action sul file di mapping, altrimenti… la configurazione di NHibernate non funzionerà. Ad essere precisi questo si potrebbe evitare, ma per farlo dovremmo distribuire i file di mapping insieme all’applicazione, ed è un’opzione che francamente non mi piace e nemmeno ho mai visto praticare.

Fatto questo non rimane che scrivere difatto il mapping. In questo primo test useremo solo tre elementi di mapping: class,key e property, praticamente il minimo indispensabile per avere un entità al lavoro. Approfondiremo i vari aspetti nelle prossime parti.

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="NHFromScratch.Entities" 
   3:                                                       assembly="NHFromScratch.Entities">
   4:   <class name="Customer" table="Customers">
   5:     <id name="Id" type="Int32">
   6:       <generator class="native"/>
   7:     </id>
   8:     <property name="Name" type="String" not-null="true"/>
   9:     <property name="AddressLine1" type="String" not-null="true"/>
  10:     <property name="AddressLine2" type="String" />
  11:     <property name="City" type="String" not-null="true"/>
  12:     <property name="ZipCode" type="String" not-null="true"/>
  13:     <property name="Active" type="Boolean" not-null="true"/>
  14:   </class>
  15:   
  16: </hibernate-mapping>
  17:  
  18:  
  19:  

Facciamo tuttavia due parole per dire a grandi linee cosa contiene il mapping della entità Customer. Innanzitutto è specificato il namespace e l’assembly che contiene l’entità mappata. Questo non è obbligatorio, ma ci consente di scrivere in maniera più leggibile il nome della classe più avanti. Il tag class indica appunto la classe che intendiamo utilizzare come entity. Ricordiamo che spesso non esiste un rapporto 1:1 tra tabelle ed entità, ms in questo semplice esempio così accadrà. Il tag class ci permette di definire il nome della classe, e a quale tabella è associata su DB. Il tag più sotto <id> è necessario: NHibernate vuole sapere come il database “distingue” le entità. Ci sono svariati modi per fare questo, e ll modo viene scelto dal sotto-tag generator: in questo esempio abbiamo specificato un generator “native”, che significa id univoco assegnato dal DB ( identity, auto-incrementale ) comunque esso si chiami nel DB target. Successivamente vengono le proprietà, con i loro bei nomi e tipi dato. Noterete che non ho specificato nessun nome per la corrispondente colonna sul DB: semplicemente se  il nome è uguale nessuno ci obbliga a farlo, non ripetiamo noi stessi. Anzi, diciamo anche che il tipo sarebbe un surplus se scrivessimo a mano la classe sottostante: NHibernate usa molto inferire le informazioni ovunque sia possibile. Noi però la classe non abbiamo voglia di farla a mano, per cui ci serviamo di hbm2net ( vedi la parte 1 ). Per scatenare questo tool, usiamo un pre build step di Visual Studio, come quello qui sotto:

t6

in pratica diciamo ad hbm2net di lavorare su tutti i file .hbm.xml che trova nella sottocartella mapping della solution, di mettere gli output ( ovvero le classi ) nella cartella del progetto. Sebbene hbm2net sia un editor template based che può generare un po’ qualsiasi artefatto partendo dall hbm, senza parametri si limita a generare le classi corrispondenti al mapping. Lanciando la build nell’output dovreste vedere il progress anche di hbm2net:

t7

Finita la build, vi trovate il file autogenerato per la entity su file system. Aggiungetelo al progetto.

t8

Date un’occhiata alla classe autogenerata, date un occhiata anche al mapping: se avete provato qualche altro tool per NH noterete che il lavoro fatto finora sembra molto semplificato. Stiamo scrivendo solo lo stretto indispensabile, quello che non ci serve lo lasciamo assolutamente da parte, perchè questo è NHibernate da ZERO.

t9

Bene, per completare la solution aggiungiamo la reference ad NHibernate: NHibernate e Iesi.Collection sono gli unici assembly che dobbiamo referenziare a tempo di build.

E’ finalmente l’ora di andare in test. Aggiungiamo alla solution un progetto di tipo Class Library, in cui inseriremo gli unit test.

t10

La solution di test, in modo simile ad un progetto che deve andare in produzione, necessita delle reference non statiche di NHibernate. Noi le abbiamo nella cartella Lib della solution, dobbiamo spostarli a fianco della dll di produzione. Possiamo scegliere di farlo con un post-build step, come illustrato qui sotto.

t11

Anche le reference di questo progetto sono un po’ più impegnative: ci serve Iesi.Collection & NHibernate come al solito, ma anche il nostro assembly con le entità, log4net per il logging, ed in più, ovvviamente, nunit.framework, va da sè.

t12

A me personalmente piace la barra verde di NUnit, per cui testiamo il progetto con NUnit, mettendo NUnit.exe come “start external program”.

t13

A questo punto creiamo il nostro unit test, con lo scopo di configurare NH, un po’ di log, e vedere se riusciamo a creare il Database. Sì, in questo tutorial il database non lo facciamo a mano, perchè anche se questo è NHibernate da ZERO, vogliamo scrivere il meno codice possibile.

Il codice dello unit test è qui di seguito:

   1: namespace NHFromScratch.Tests
   2: {
   3:     [TestFixture]
   4:     public class TestCustomer
   5:     {
   6:         static TestCustomer()
   7:         {
   8:             ConfigureLogForNet();
   9:         }
  10:  
  11:         ISessionFactory sessionFactory;
  12:         [SetUp]
  13:         public void Setup()
  14:         {
  15:             
  16:             CreateSessionFactory();
  17:         }
  18:  
  19:         [Test]
  20:         public void CanCreatedatabse()
  21:         {
  22:             SchemaExport export = new SchemaExport(CreateConfiguration());
  23:             export.Execute(true, true, false);
  24:         }
  25:  
  26:         [Test]
  27:         public void CanPersistCustomer()
  28:         {
  29:             Console.WriteLine("\n****** SAVE A CUSTOMER ********");
  30:             //save a customer
  31:             using (var session = sessionFactory.OpenSession())
  32:             using(var transaction = session.BeginTransaction())
  33:             {
  34:  
  35:                 Customer c = new Customer()
  36:                 {
  37:                     Active = true
  38:                      ,
  39:                     AddressLine1 = "xxxx"
  40:                      ,
  41:                     City = "Cuneo"
  42:                      ,
  43:                     Name = "Bill Gates"
  44:                      ,
  45:                     ZipCode = "12060"
  46:                 };
  47:                 session.Save(c);
  48:                 transaction.Commit();
  49:             }
  50:             Console.WriteLine("\n****** RETRIEVE A CUSTOMER ********");
  51:             //retrieve a customer
  52:             using (var session = sessionFactory.OpenSession())
  53:             
  54:             {
  55:  
  56:                 var customer = session.CreateCriteria<Customer>()
  57:                     .Add(Expression.Eq("Name", "Bill Gates"))
  58:                     .UniqueResult();
  59:  
  60:                 Assert.NotNull(customer);
  61:             }
  62:  
  63:             Console.WriteLine("\n****** MODIFY A CUSTOMER ********");
  64:             //modify a customer
  65:             using (var session = sessionFactory.OpenSession())
  66:             using (var transaction = session.BeginTransaction())
  67:             {
  68:  
  69:                 var customer = session.CreateCriteria<Customer>()
  70:                     .Add(Expression.Eq("Name", "Bill Gates"))
  71:                     .UniqueResult<Customer>();
  72:                 customer.ZipCode = "0000";
  73:                 Assert.NotNull(customer);
  74:                 
  75:                 transaction.Commit();
  76:             }
  77:  
  78:  
  79:             Console.WriteLine("\n****** VERIFY CUSTOMER IS MODIFIED ********");
  80:             //verify mod
  81:             using (var session = sessionFactory.OpenSession())
  82:             {
  83:  
  84:                 var customer = session.CreateCriteria<Customer>()
  85:                     .Add(Expression.Eq("Name", "Bill Gates"))
  86:                     .UniqueResult<Customer>();
  87:                 
  88:                 Assert.NotNull(customer);
  89:                 Assert.AreEqual("0000", customer.ZipCode);
  90:             }
  91:  
  92:  
  93:             Console.WriteLine("\n****** DELETE A CUSTOMER ********");
  94:             //delete a customer
  95:             using (var session = sessionFactory.OpenSession())
  96:             using (var transaction = session.BeginTransaction())
  97:             {
  98:  
  99:                 var customer = session.CreateCriteria<Customer>()
 100:                     .Add(Expression.Eq("Name", "Bill Gates"))
 101:                     .UniqueResult();
 102:                 session.Delete(customer);
 103:                 transaction.Commit();
 104:             }
 105:             Console.WriteLine("\n****** VERIFY CUSTOMER IS DELETED ********");
 106:             //verify delete
 107:             using (var session = sessionFactory.OpenSession())
 108:             
 109:             {
 110:  
 111:                 var customer = session.CreateCriteria<Customer>()
 112:                     .Add(Expression.Eq("Name", "Bill Gates"))
 113:                     .UniqueResult();
 114:                 Assert.IsNull(customer);
 115:             }
 116:         }
 117:  
 118:  
 119:  
 120:         private static void ConfigureLogForNet()
 121:         {
 122:             TraceAppender app = new TraceAppender();
 123:             app.Layout = new SimpleLayout();
 124:             //BasicConfigurator.Configure( app);
 125:         }
 126:  
 127:         private void CreateSessionFactory()
 128:         {
 129:             Configuration cfg = CreateConfiguration();
 130:             sessionFactory = cfg.BuildSessionFactory();
 131:         }
 132:  
 133:         private static Configuration CreateConfiguration()
 134:         {
 135:             Configuration cfg = new Configuration();
 136:             cfg.Configure();
 137:             // implicitamente carichiamo tutti i mapping che si trovano nell'assembly che
 138:             // contiene customer
 139:             cfg.AddAssembly(typeof(Customer).Assembly);
 140:             return cfg;
 141:         }
 142:  
 143:  
 144:     }
 145: }

Fatto questo lanciamo il test “CanCreateDatabase” e, come probabilmente sospettiamo, andiamo in rosso con il logger che dice qualcosa come qua sotto:

t14

In effetti, ci siamo “dimenticati” di configurare NHibernate, per cui a che DB potrebbe mai puntare ? Come vedete avere il log abilitato lascia pochi dubbi rispetto a quale sia l’errore. Tra l’altro manca persino il database…

Quindi creiamo prima un database vuoto, non serve fare nessuna tabella, lasciamo che sia NHibernate a fare il lavoro sporco

t16

 

Nell’esempio ho creato un database con nome NHFROMSCRATCH sull’SQLEXPRESS locale. Poi tornando alla  , quando si vedeva il contenuto dello ZIP, rocorderete la cartella Configuration_Templates: in questa cartella ci sono appunto dei template di configurazione, in cui basta sostituire un po’ di cose per essere pronti a lavorare con il db scelto:

t15

Nel nostro caso scegliamo MSSQL. Il contenuto del file, dopo le modifiche del caso è questo:

   1: <?xml version="1.0" encoding="utf-8" ?>
   2:  
   3:  
   4: <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
   5:   <session-factory name="NHibernate.Test">
   6:     <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
   7:     <property name="connection.connection_string">Server=.\SQLEXPRESS;initial catalog=NHFROMSCRATCH;Integrated Security=SSPI</property>
   8:     <property name="adonet.batch_size">10</property>
   9:     <property name="show_sql">true</property>
  10:     <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
  11:     <property name="use_outer_join">true</property>
  12:     <property name="command_timeout">60</property>
  13:     <property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
  14:     <property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
  15:   </session-factory>
  16: </hibernate-configuration>

 

Come si vede, le modifiche sostanziali sono nella proprietà connection string, e in show_sql, che ho messo a true, per visualizzare le query mentre NH le esegue: un trucco che ci permetterà non tanto di vedere come NHibernate fa le query, ma piuttosto quante ne fa, per fare performance tuning. Questa sessione di configurazione potrà essere messa nel file di configurazione dell’applicazione, o vicino al file binario che la usa in un file di nome hibernate.cfg.xml, soluzione scelta nell’esempio.

t17

Ricordiamoci che, dopo aver inserito il file hibernate.cfg.xml nel progetto, dobbiamo impostare il flag “copy if newer” cosicchè verrà copiato automaticamente nella cartella di uscita.

vediamo ora come è fatto il test “CanCreateDatabase”:

   1: [Test]
   2: public void CanCreatedatabse()
   3: {
   4:    SchemaExport export = new SchemaExport(CreateConfiguration());
   5:    export.Execute(true, true, false);
   6: }

 

Usiamo la classe di Helper SchemaExport: questa classe, partendo dalla Configurazione corrente, si occupa di effettuare la creazione dello schema del database. Ora lanciando il test questi si comporta meglio, e nella porzione console è possibile  vedere la DDL che è stata inviata al database.

 

t18

Tramite il flag della funzione Export, è possibile sottometere lo script al sistema database sottostante, nel nostro caso otterremo su DB l’unica tabella del nostro minuscolo modello di test:

t19

Quindi facciamo un breve recap fino a questo punto: con un solo file ( il mapping appunto ) abbiamo creato un database e il codice c#. Tutto questo grazie ad hbm2net, che è un code generator open source recuoperabile da NHContrib. Con un po’ di pazienza è possibil emodificare e/o scrivere template aggiuntivi per hbm2net per geenrare altri tipidi artefacts, ad esempio DTO o altro, ma questo sarà visto più avanti. In pratica possiamo vedere hbm2net come un generatore di codice programmabile, che di default produce il codice delle entity partendo dai file hbm.

t18b

 

Ora possiamo scrivere il codice di prova per il modello. Mettendo a “true” il valore di show_sql nella configurazione, NH manda in standard output le query, per cui in debug è possibile ispezionare cosa succede dietro le quinte. Il nostro semplice unit test crea/modifica/cancella una semplice istanza della entità customer, eco il codice dello unit test che fa tutto questo:

   1: namespace NHFromScratch.Tests
   2: {
   3:     [TestFixture]
   4:     public class TestCustomer
   5:     {
   6:         static TestCustomer()
   7:         {
   8:             ConfigureLogForNet();
   9:         }
  10:  
  11:         ISessionFactory sessionFactory;
  12:         [SetUp]
  13:         public void Setup()
  14:         {
  15:             
  16:             CreateSessionFactory();
  17:         }
  18:  
  19:         [Test]
  20:         public void CanCreatedatabse()
  21:         {
  22:             SchemaExport export = new SchemaExport(CreateConfiguration());
  23:             export.Execute(true, true, false);
  24:         }
  25:  
  26:         [Test]
  27:         public void CanPersistCustomer()
  28:         {
  29:             Console.WriteLine("\n****** SAVE A CUSTOMER ********");
  30:             //save a customer
  31:             using (var session = sessionFactory.OpenSession())
  32:             using(var transaction = session.BeginTransaction())
  33:             {
  34:  
  35:                 Customer c = new Customer()
  36:                 {
  37:                     Active = true
  38:                      ,
  39:                     AddressLine1 = "xxxx"
  40:                      ,
  41:                     City = "Cuneo"
  42:                      ,
  43:                     Name = "Bill Gates"
  44:                      ,
  45:                     ZipCode = "12060"
  46:                 };
  47:                 session.Save(c);
  48:                 transaction.Commit();
  49:             }
  50:             Console.WriteLine("\n****** RETRIEVE A CUSTOMER ********");
  51:             //retrieve a customer
  52:             using (var session = sessionFactory.OpenSession())
  53:             
  54:             {
  55:  
  56:                 var customer = session.CreateCriteria<Customer>()
  57:                     .Add(Expression.Eq("Name", "Bill Gates"))
  58:                     .UniqueResult();
  59:  
  60:                 Assert.NotNull(customer);
  61:             }
  62:  
  63:             Console.WriteLine("\n****** MODIFY A CUSTOMER ********");
  64:             //modify a customer
  65:             using (var session = sessionFactory.OpenSession())
  66:             using (var transaction = session.BeginTransaction())
  67:             {
  68:  
  69:                 var customer = session.CreateCriteria<Customer>()
  70:                     .Add(Expression.Eq("Name", "Bill Gates"))
  71:                     .UniqueResult<Customer>();
  72:                 customer.ZipCode = "0000";
  73:                 Assert.NotNull(customer);
  74:                 
  75:                 transaction.Commit();
  76:             }
  77:  
  78:  
  79:             Console.WriteLine("\n****** VERIFY CUSTOMER IS MODIFIED ********");
  80:             //verify mod
  81:             using (var session = sessionFactory.OpenSession())
  82:             {
  83:  
  84:                 var customer = session.CreateCriteria<Customer>()
  85:                     .Add(Expression.Eq("Name", "Bill Gates"))
  86:                     .UniqueResult<Customer>();
  87:                 
  88:                 Assert.NotNull(customer);
  89:                 Assert.AreEqual("0000", customer.ZipCode);
  90:             }
  91:  
  92:  
  93:             Console.WriteLine("\n****** DELETE A CUSTOMER ********");
  94:             //delete a customer
  95:             using (var session = sessionFactory.OpenSession())
  96:             using (var transaction = session.BeginTransaction())
  97:             {
  98:  
  99:                 var customer = session.CreateCriteria<Customer>()
 100:                     .Add(Expression.Eq("Name", "Bill Gates"))
 101:                     .UniqueResult();
 102:                 session.Delete(customer);
 103:                 transaction.Commit();
 104:             }
 105:             Console.WriteLine("\n****** VERIFY CUSTOMER IS DELETED ********");
 106:             //verify delete
 107:             using (var session = sessionFactory.OpenSession())
 108:             
 109:             {
 110:  
 111:                 var customer = session.CreateCriteria<Customer>()
 112:                     .Add(Expression.Eq("Name", "Bill Gates"))
 113:                     .UniqueResult();
 114:                 Assert.IsNull(customer);
 115:             }
 116:         }
 117:  
 118:  
 119:  
 120:         private static void ConfigureLogForNet()
 121:         {
 122:             TraceAppender app = new TraceAppender();
 123:             app.Layout = new SimpleLayout();
 124:             //BasicConfigurator.Configure( app);
 125:         }
 126:  
 127:         private void CreateSessionFactory()
 128:         {
 129:             Configuration cfg = CreateConfiguration();
 130:             sessionFactory = cfg.BuildSessionFactory();
 131:         }
 132:  
 133:         private static Configuration CreateConfiguration()
 134:         {
 135:             Configuration cfg = new Configuration();
 136:             cfg.Configure();
 137:             // implicitamente carichiamo tutti i mapping che si trovano nell'assembly che
 138:             // contiene customer
 139:             cfg.AddAssembly(typeof(Customer).Assembly);
 140:             return cfg;
 141:         }
 142:  
 143:  
 144:     }
 145: }

Ed ecco uno screenshots di come NH opera dietro le quinte:

t20

Nella prossima parte vedremo meglio i dettagli del file di mapping e il tag <many-to-one> insieme a <bag>.

 

 

Download Sorgenti

Parte 1

Wednesday, September 01, 2010 8:11:59 PM (GMT Daylight Time, UTC+01:00)  #    Comments [2] - Trackback
NHibernate | NHibernate Tutorial
# Saturday, August 28, 2010
Vai alla parte 2: Creare un progetto

Mi è ventuta l’idea di produrre una serie di post che consentano a chi vuole iniziare a lavorare con NHibernate, o almeno a provare per vedere se questo OR/M è la scelta giusta, di creare in modo ordinato un ambiente di test pulito, sapendo bene cosa serve, evitando il percorso “pasticciato” che spesso si fa all’inizio.

Bene, come partenza bisogna scaricare NHibernate. Il posto giusto dove farlo è il progetto su sourceforge, e il modo giusto di farlo è procurare i file binary necessari. Scaricare i sorgenti per il momento può essere tranquillamente tralasciato. Puntando al link di download, vi trovate qualcosa del genere:

s1

Come vedete ci sono più versioni, ed anche una ultima release, che in questo caso è la 3.0.0 Alpha2. Io ho cerchiato la versione 2.1.2 GA che è quella che useremo per questa serie di articoli, ma ho anche cerchiato GA: “general availability”. Dunque, perchè non ho scaricato l’ultima versione ? Cosa significa GA ? NHibernate ha una politica di rilascio ben consolidata, e marca con GA le versioni “da produzione”. Quindi, se non siete a conoscenza di qualche funzionalità particolare che c’è solo nella alpha di turno, se non siete dell’idea di vedervi cambiate sotto il naso funzioni e comportamenti, scaricate le versioni GA più recenti che trovate. Non esistono al momento “Setup” di NHibernate, mi risulta che ci fosse qualcosa in passato, comunque anche se trovaste qualcosa, vi suggerisco di evitarlo: NH consente di fare un private deploy, e avere traccia di quello che serve ci sarà utile in fase di consegna dell’applicativo sulle macchine di produzione. Scarichiamo quindi il file NHIbernate-2.1.2.GA-bin.zip. Scaricato il file il layout del contenuto è quello schematizzato qui sotto:

s2

Nella root, oltre ad un po’ di paccottiglia varia, troviamo due folder importanti che sono quelli che ci servono per mettere NHibernate all’opera: Required_Bins, and Required_For_LazyLoading.Tutte le dll contenute nel file required bin devono essere rilasciate insieme all’applicazione ( oltre a servire ovviamente  in fase di sviluppo :) ), mentre dalla cartella Required_For_LazyLoading si può scegliere quale folder distribuire in base a quale proxy generator si sceglie. Questo è un tema che si vedrà più avanti, per adesso basta sapere che NHibernate può derivare internamente alcune delle nostre classi quando decidiamo di avere delle entità “Lazy”, e questo è ottenuto tramite delle librerie esterne di generazione di classi “proxy”. Quale proxy generator usare dipende dalla configurazione, e quindi dalla stessa configurazione dipende quale folder distribuire. Negli esempi useremo LinFu. Diciamo che questa scelta è di scarso impatto sulla vita del vostro progetto, salvo in situazioni particolari, per cui per il momento possiamo andare avanti.

Importantissimi in fase di sviluppo sono i file nhibernate-mapping.xsd e nhibernate-configuration.xsd. Questi due file vi consentono di avere l’intellisense abilitato per i file di mapping e per la configurazione, e quindi sono assolutamente indispensabili. Malgrado siano finiti nella cartella required_bin, sono invece praticamente inutili in fase di distribuzione. Per attivare l’intellisense occorre copiare i due file suddetti nella cartella apposita di visual studio:

s3

Attenzione: può succedere che imporvvisamente Visual Studio smetta di fornire l'intellisense: tipicamente questo accade perchè ci sono più versioni dello stesso schema XML associate. Date un occhiata a questo post che spiega come risolvere il problema.

Inoltre, per sviluppare e per seguire gli esempi in questo tutorial occorrerà NUnit. Se ce lo avete già usate quello, altrimenti recuperate l’ultima versione dal sito ufficiale. Io di solito scarico il binario, non il setup, e lo scompatto sotto il folder programmi. Anche NUnit funziona con il semplice deploy Xcopy.

Ultima cosa prima di partire, lavorando con NHibernate ci sono alcune attività ripetitive che sarebbe bello evitare: consiglio di scaricare anche il tool hbm2net che ci consentirà di generare automaticamente le classi per nel corso del tutorial. Il tool si trova nel progetto NHContrib. Scaricate e scompattate lo zip in un folder, per esempio in C:\hbm2net. Il tool è un compilatore linea di comando, e sarà lanciato automaticamente da Visual Studio, ma perchè ciò avvenga occorre aggiungere la cartella in cui avete messo hbm2net nella variabile di ambiente PATH. per fare questo raggiungete le “proprietà del Sistema”:

s5

e poi aggiungere il path suddetto alla variabile PATH:

s6

 

Nella Parte2 vediamo come organizzare un progetto con NH.

Saturday, August 28, 2010 12:57:29 PM (GMT Daylight Time, UTC+01:00)  #    Comments [5] - Trackback
NHibernate | NHibernate Tutorial
# Wednesday, August 11, 2010

For maintenance reasons sometime the original NHForge location is not available. In such a case you can download the file containing the binary release of the tools in the original NHContrib project download location:

nhcontribdownload

Wednesday, August 11, 2010 9:10:41 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
db2hbm | hbm2net | NHibernate
# Saturday, July 31, 2010

 José Romaniello is doing progress in hql intellisense for Visual Studio 2010. He manage to integrate some NHWorkbench codebase into it, to have some intellisense working. Even if the project is still in alpha, I suggest you to download and install to give it a try.

Here below a screenshot of the tool at work:

 

image

Nice, isn’t it ?

As an addition I was added to the project by Josè, and I would be happy to add some contribution to this important project for the NHibernate ecosystem.

Saturday, July 31, 2010 3:27:17 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
HQL language Service | NHibernate
# Wednesday, July 14, 2010

Apprendo da questo post di Fabio Maulo una interessante feature di NHibernate 3 implementata nel nuovo subset di API: QueryOver. Il post di Fabio approfondisce il pattern Query Object, e quello che salta all’occhio è la pulizia con cui si riesca finalmemte a farte un paging “ad arte”. Per fare l’accesso paginato in generale occorre avere il count delle righe che il sistema vorrebbe tornarci, e questo constringeva in passato a fare delle implementazioni un po’ sporche in cui si era costretti a specificare la query di selezione e quella di count. QueryOver propone la funzione query.ToRowCountQuery(); – dove query è appunto una query di QueryOver, e la funzione ci restituisce la query di conteggio in modo pulito e trasparente. Assolutamente molto utile. Io non sono uno da trunk, ma una funzione del genere mi fa venire voglia di passare subito a NH3, ancor prima che venga rilasciata la GA.

Wednesday, July 14, 2010 8:50:20 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
NHibernate
# Monday, June 14, 2010

bug The right place for bug reporting or requiring additional features is

here

Since the project is new, it is normal to have something to fix. The problem is that my testing would just be not sufficient, so your help will really be appreciated. Thanks!

Monday, June 14, 2010 4:31:59 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
Code GEneration | NHibernate | NHWorkBench
# Saturday, June 05, 2010

With a little delay I found people complaining about the schema file missing from the db2hbm deployed package. Now the file is included in the download package, and yanch provided a shortcut in the doc to download the file from sourceforge. Thanks!

Well, a few word about db2hbm and Oracle ( and any other database but MSSQL now ). I used the schema information provided by NH as long as possible, but these information does not provides the required details in order to discover completely the foreign keys, and foreign keys are necessary for creating associations. Not really an NH problem, actually NH leverages ADO.NET for schema inquiry, but ADO.NET seems to miss the foreign key part. So the only solution to have db2hbm working for all database is to provide a custom foreign key crawler for the DB.

Saturday, June 05, 2010 2:32:40 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
Code GEneration | NHibernate
# Monday, May 31, 2010

First of all I renamed the project on Sourceforge. Now it is more sensible NHibernate Workbench.

nhwsourceforge

In the SVN repository there is now a tag to the version 1.0.0.11, and the trunk claim to be the version 1.0.0.2.00.

Now I’m planning to allow to use NH Workbench attached to a running application: this should help us to play with application compiled without mappings ( ie ConfOrm and Fluent NH ). Then I would like to improve the “Probe” class letting it be more versatile and modifiable by the user, probably using some sort of script engine: I’m thinking to use IronPython, but any suggestion are welcome. Just to clarify: the probe class serves to insolate NHWorkbench from the NH version used by the project under test. We basically runs the test in a separate app domain, but we need the “probe” type to be unbounded to any NH specific version. This is done by using reflection, but it would be easier to be done in a script. The same engine will be useful to write some NHibernate testing: instead of use just HQL, we will be able to submit some portion of code on the fly and see what happen. The other step is to allow the user writing a mapping on the fly and imemdiately see what happen ( by using hbm2net behind the scenes ). Ok, it’s a lot of work, I’ve no idea the order this will be done, let me know if you have any idea and preference.

Monday, May 31, 2010 11:35:43 AM (GMT Daylight Time, UTC+01:00)  #    Comments [1] - Trackback
Code GEneration | HQL Intellisense | NHibernate | NHWorkBench
# Monday, May 24, 2010

Sometimes I receive some notification on where source code for both db2hbm and hbm2net are located. The best way is to check-out the source of the NHContrib project: https://nhcontrib.svn.sourceforge.net/svnroot/nhcontrib

hbm2net is still in alfa, but I frequently use it in my projects as a class generator. It really lack some documentation: it is really a powerful artifact generator, and by writing proper T4 templates any artifact can be generated. Db2hbm is working ok for MSSQL, but there is not yet an implementation for oracle and other DB, even if Ricardo Peres provided me some interesting code to work on.

Hope this help who’s looking for these tools source code.

Monday, May 24, 2010 8:08:30 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
Code GEneration | NHibernate
# Saturday, May 22, 2010

Just looking around for some related NHibernate projects, I found this open source profiler. For people who start to use NHibernate and before to buy something more accurate as NHProf, it is really useful having a log easy to read to discover performance or bad usage issues.

Saturday, May 22, 2010 9:27:01 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
NHibernate

As you probably guess, the Fatica.Labs.HqlEditor evolved as a component used by NH Workbench, that is basically a tool ispired by the old and wise NHQA by Ayende. There is, in comparison, some new ideas and some missing required functions. Anyway I decided to publish a first drop because it already help me on my day job. If you find the project useful please consider visits the following links:

And, if you want to join the project, please let me know.

Saturday, May 22, 2010 6:55:49 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
HQL Intellisense | NHibernate | NHWorkBench
# Wednesday, May 19, 2010

In the spirit of “Release early. Release often. And listen to your customers” ( cit. ), even if not so early in term of time since the preview, I decided to release a first drop of the “HQL Intellisense thing” I’m working on. The current version is just able to load an existing mapping assembly, a configuration, help us to write an hql query, submit it to NH and see some results. Here an overall screenshot:

s1

To use it you need to download the bits, and then “create a project” a project is, in the NH Workbench world, a bounch of file representing what we are working on ( and actually is a project in the MSBUILD world. To use the tool now we need at least a working NH configuration file ( your app.config or web config ) and one or more mapping assembly(ies). You add the files to the project by right clicking the project tree:s2

After you added the file you can save the project, so it can be reopened when needed. Please note that the mapping assembly has to be opened from a location containing all the required dependencies ( usually the application folder, or the bin folder ).

After the project is created, you need to compile it before starting to write the queries:

s3

You can compile the project by clicking the button on the toolbar as shown in the picture Fig3

 

 

 

Compiling the project should produce a report in the log area:

s4

If you find the report too verbose, you can uncheck some of the button in the log toolbar. After a successful compilation, we can open a query (hql) document:

s5

This will open a pane in the document area in which we can write HQL queries with some intellisense/auto-completion. Plaese note that, for have the entity completion, after the “from” keyword we need to press ctrl+space to see the completion combo.

 

 

 

 

 

 

s6

Here an example HQL document. After a valid query is done we can submit it to NH and see the result:

 

The “play” button is enabled only if a valid query ( no errors ) is written in the document. The first and count places are useful to limit the query results.

s7 By pressing the play button, you will be able to se the query results ( if any ):

s8

Next steps:

  • Solve the bugs till now
  • Add supports for hbm2net, so user can write mapping and immediately see it at works.

Enjoy !

Wednesday, May 19, 2010 4:30:52 PM (GMT Daylight Time, UTC+01:00)  #    Comments [10] - Trackback
Code GEneration | NHibernate

There was a bug in the many-to-many strategy, causing a null reference exception. The bug was solved, and a current snapshot of db2hbm can be found here as usual.

db2hbm

Wednesday, May 19, 2010 10:13:46 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
Code GEneration | NHibernate
# Thursday, May 13, 2010

clip_image001

 

Fabio Maulo propone un sondaggio per la versione di NH in uscita. Dovrà compilare su Fx 3.5 o 4.0 ?

Personalmente preferirei ancora un uscita in 3.5. Votate!

Thursday, May 13, 2010 7:53:23 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
NHibernate
# Thursday, April 29, 2010

s9cThere is some interesting news with HqlEditor: now it is able to translate the query using the proper parser ( Antlr or Classic ) depending on the NH version used to build the assembly in test. An error message is shown when the syntax is parsed as invalid.

 

 

 

 

 

 

 

A first table containing the entities is present too, here below a screenshot:

s10a

As you can probably notice, the data grid is not a real grid. This is because is not so easy to present an NH graph without converting it in some sort of DTO, but I don’t want to add anything but the query process itself. So I decided to use a sort of JSON serializer to present each object in a textual fashion. In the toolbar there is the query limit too: this act by adding a SetFirstResult(), SetMaxResults() function call in the query creation. Using a count=0 forces the system to avoid limiting the query: if the data you retrieve is a big bounch you will probably experience some delay, but should be useful in the case the driver does not support limits.

Thursday, April 29, 2010 5:09:29 PM (GMT Daylight Time, UTC+01:00)  #    Comments [1] - Trackback
HQL Intellisense | NHibernate | NHWorkBench
# Tuesday, April 27, 2010

Per abilitare il logging delle query con NHibernate occorre:

  1. Avere nella bin dell applicativo ( ie: nella /bin per le applicazioni web, a fianco dell’ esequibile per le applicazioni stand-alone ) la dll di log4net.
  2. Aggiungere nel file di configurazione la sessione di config per log4net:
  3. <configuration>
      <configSections>
        <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>

      </configSections>
      <log4net>
        <appender name="console" type="log4net.Appender.ConsoleAppender">
          <layout type="log4net.Layout.PatternLayout">
            <param name="ConversionPattern" value="%-5p - %m%n" />
          </layout>
        </appender>
        <logger name="NHibernate.SQL" additivity="false">
          <level value="ALL"/>
          <appender-ref ref="console" />
        </logger>
        <root>
          <priority value="WARN" />
          <appender-ref ref="console" />
        </root>
      </log4net>
    </configuration>

    Con questa configurazione si usa il console appender, per un’applicativo web potrebbe essere meglio usare un TraceAppender o un altro appender di proprio gusto ;-)

     

  4. Assicurarsi di chiamare, almeno una voltanell’applicazione log4net.XmlConfigurator.Configure()
  5. Aggiungere questa proprietà nella configurazione di NH:                                         <property name="show_sql">true</property>

Se NON vogliamo mettere nulla di log4net nella configurazione:

Possiamo configurare log4net dall’ applicativo, con un paio di linee di codice:

   1:              TraceAppender app = new TraceAppender();
   2:              app.Layout = new SimpleLayout();
   3:              LoggerMatchFilter filter = new LoggerMatchFilter();
   4:              filter.LoggerToMatch="NHibernate.SQL";
   5:              filter.AcceptOnMatch = true;
   6:              filter.ActivateOptions();
   7:              app.AddFilter(filter); // L'ordine di questo filtro
   8:              app.AddFilter(new DenyAllFilter()); // e di quest'altro E' importante
   9:              app.ActivateOptions();
  10:              BasicConfigurator.Configure( app);
 
 
 

In questo caso si possono saltare gli step da 1 a 3. Questo codice deve essere chiamato una volta nell’applicazione in fase di startup, per un’applicazione web, potrebbe andare bene l’evento di startup dell'applicazione in global.asax. Con l’appender e i filtri configurati si ottiene nell'area trace di Visual Studio ( Output-tab Debug)  l’output delle sole query generate da NH ( senza gli altri logger, se servono  si possono togliere i filtri )

Tuesday, April 27, 2010 4:43:20 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
NHibernate | log4net
# Sunday, April 25, 2010

Mauricio Scheffer has just released a web based console for editing HQL. He based the intellisense on my project. I’m happy to see some of my effort reused somewhere! So thanks to Mauricio.

Sunday, April 25, 2010 10:29:44 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
HQL Intellisense | NHibernate
# Thursday, April 22, 2010

There is some interesting progress with my project Fatica.Labs.HqlEditor. I just want to share some screenshot:

s5

Well, it is growing to be a real tool, and in my idea would became a sort of test bed in which the user can add or modify mapping, try the queries, change the config, export a database script, reverse engineering and so on. Actually all the low level tool to achieve that are available.

Ok, let’s explain the layout:

  1. The document area, here we have mapping/config/hql all with intellisense. In the screenshot the code completion for an Hql is shown. In future maybe I will be able to insert a T4 editor for the hbm2net templates.
  2. The project area: here we have a bounch of file that are representing our testing project: mapping, configurations, assemblies and so on. I have use the MSbuild object as a backend for the project, because in the near future I would like to use it to really build some artifacts using hbm2net and db2hbm.
  3. Here is the SQL preview of the query in editing. Now the view is showing an error because the query is incomplete.
  4. The funny log, a graphical appender for log4net :-)

Some more words about the project itself: the testing environment is hosted in a separate appdomain, this will allow us to:

  • Modify the mapping runtime generating new version of the assembly
  • Testing production assemblies built with legacy nh versions ( well, not so legacy, starting from 2.xxx )

Let’s have another screenshot, showing a real SQL preview:

s7

Next step is to produce the query results in some sort of usable representation ( I need to push the data across two app domain ) so I would probably use some JSON serialization and then display the JSON raw data with some readable formatting.

You can see a little demo video here.

The project is not yet released, please treat it as a CTP ;) anyway, the svn repository is here:

https://faticalabshqled.svn.sourceforge.net/svnroot/faticalabshqled

Thursday, April 22, 2010 5:41:58 PM (GMT Daylight Time, UTC+01:00)  #    Comments [2] - Trackback
Code GEneration | HQL Intellisense | NHibernate | NHWorkBench
# Tuesday, April 20, 2010

Fabio Maulo sta proponendo una nuova astrategia di mapping per NHibernate: ConfORM. In pratica si tratta di una strategia code only, quindi nessun file di XML, ma tutto via codice con l’approccio fluent interface. Stranamente la community si è un po’ stupita di vedere un ennesima strategia, e tutti stanno lì a chiedersi il perchè. Bene, il perchè è che è una nuova possibilità di scelta, ed avere molte scelte è un plus degli ambienti open source. In un suo post Fabio disegna uno scenario completo della ricca rosa di partecipanti al problema mapping. Difatto ConfORM è l’unica API che sfonda completamente lo strato hbm, e va direttamente alla radice. Tutto questo si traduce immediatamente in un incremento di performance, ed in una migliore linearità progettuale: meno strati è meglio, anzi, meno strati inutili è meglio. Francamente, dopo una piccola esperienza acquisita nel problema mapping con la scrittura del tool NHModeller, ho deciso di tornare ed imparare la strategia HBM. Dopo un po’ non è così male, ma la prossima volta che faccio un progetto mio provo ad usarlo ( in azienda non se ne parla nemmeno: già il mapping XML è visto come una stregoneria, e c’è chi legifera che mappare le foreign Key come long sia una buona idea anzichè un antipattern ;-) ).

In conclusione: chissenefrega se un nuovo sistema sembra essere il duplicato di un altro:Vincerà il migliore, ed in ogni caso il migliore secondo gli utilizzatori :-)

Tuesday, April 20, 2010 7:22:46 PM (GMT Daylight Time, UTC+01:00)  #    Comments [6] - Trackback
ConfORM | NHibernate
# Tuesday, March 30, 2010

If anybody still uses HQL with NHibernate, it would probably find useful some editing with intellisense.

Using the SharpDevelop Text Editor, the ANTLR grammar from the NHibernate sources, and some hacking in the java Eclipse Plugin code, the results is this:

 

Ctrl+Space completion 1: entity alias

s1

Ctrl+Space completion 2: Entity names

s2

Dot completion: property completion

 

s3

 

Ctrl+Space completion: all keywords and functions

 

s4

Here you can find the related sourceforge project.

Tuesday, March 30, 2010 4:44:42 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
HQL Intellisense | NHibernate
# Saturday, October 17, 2009

Esiste, o meglio esisteva un tool di code generation, per creare automaticamente le classi partendo dai file di mapping di NHibernate. Questo tool (hbm2net, presente in NHContrib ) è stato un po' dimenticato, per cui ho deciso di provare a riesumarlo, e di ammodernarlo un po' dandogli la possibilità di utilizzare il Text Template Transformation Toolkit (T4). Ho previsto un template interno per la semplice generazione delle classi di mapping, ma potenzialmente è possibile generare con facilità qualsiasi altro codice provvedendo un template esterno, ad esempio mascherine di UI, layer WCF etc etc.

La versione attuale è una pre-alfa, serve solo a dare un'idea, e a vedere se ci sono delle dipendenze in deploy di difficile gestione, non è ben chiaro a me se T4 sia presente  in tutte le installazioni di Visual Studio.

Se volete provare il tool  potete scaricarlo da qui. Per utilizzare il templating T4 dovete utilizzare la seguente linea di comand:

hbm2net --config=t4config.xml *.hbm.xml

è importante utilizzare il config indicato, altrimenti hbm2net defaulta sul render di NVelocity.  Verra creata una cartella generated con i file sorgenti corrisondenti agli hbm.

Potete scaricare hbm2net da qui.

Per provare al volo è incluso nello zip anche un file di mapping simple1.hbm.xml.

Fatemi avere dei feedback!

 

Saturday, October 17, 2009 3:50:00 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] - Trackback
NHibernate
Archive
<September 2010>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010
Felice Pollano
Sign In
Statistics
Total Posts: 67
This Year: 41
This Month: 2
This Week: 0
Comments: 36
This blog visits
Locations of visitors to this page
All Content © 2010, Felice Pollano
DasBlog theme 'Business' created by Christoph De Baene (delarou) and modified by Felice Pollano