NHibernate http://blogs.ugidotnet.org/DanBlog/category/NHibernate.aspx NHibernate it-IT Daniele Armanasco Subtext Version 2.6.0.0 NHibernate e i trigger di SQL Server http://blogs.ugidotnet.org/DanBlog/archive/2007/11/15/89701.aspx <p><font face="Arial">Tentando di aggiornare una entità persistita su una tabella di SQL Server dove è presente un trigger ottengo l'eccezione seguente e l'aggiornamento fallisce:</font></p> <p><font face="Arial">[NHibernate.AdoNet.TooManyRowsAffectedException] {"Unexpected row count: 2; expected: 1"} NHibernate.AdoNet.TooManyRowsAffectedException</font></p> <p>A quanto pare il fatto che il trigger aggiorni un altro record fa sì che il db ritorni 2 come numero di record aggiornati, il che fa pensare ad NH che ci sia stato un errore. Non ho trovato opzioni che dicano a NH di non verificare il numero di record aggiornati; sembra che l'unica soluzione consista nel disabilitare il conteggio dei record modificati nel trigger (impostare<font face="Arial"> SET NOCOUNT ON prima del comando di UPDATE nel trigger e impostare SET NOCOUNT OFF dopo il comando di UPDATE). Non ho trovato altre soluzioni.</font></p><img src="http://blogs.ugidotnet.org/DanBlog/aggbug/89701.aspx" width="1" height="1" /> Daniele Armanasco http://blogs.ugidotnet.org/DanBlog/archive/2007/11/15/89701.aspx Thu, 15 Nov 2007 00:35:12 GMT http://blogs.ugidotnet.org/DanBlog/archive/2007/11/15/89701.aspx#feedback 2 http://blogs.ugidotnet.org/DanBlog/comments/commentRss/89701.aspx http://blogs.ugidotnet.org/DanBlog/services/trackbacks/89701.aspx NUnit + NHibernate http://blogs.ugidotnet.org/DanBlog/archive/2007/08/16/87832.aspx <p>Per testare in NUnit i metodi di persistenza (direttamente in Persistence o tramite provider e manager), siccome normalmente la classe SessionHelper carica la configurazione di NH leggendo dall'assembly in esecuzione, e siccome usando la gui di NUnit l'assembly in esecuzione è quello del progetto NUnit,</p> <p>è necessario aggiungere al progetto di test un file di configurazione che sarà nella stessa directory del progetto NUnit collegato e che conterrà la configurazione per NH; nel progetto NUnit selezionare Project - Edit - Configurazione - File Name e indicare il nome del file di configurazione appena creato.</p><img src="http://blogs.ugidotnet.org/DanBlog/aggbug/87832.aspx" width="1" height="1" /> Daniele Armanasco http://blogs.ugidotnet.org/DanBlog/archive/2007/08/16/87832.aspx Thu, 16 Aug 2007 02:42:04 GMT http://blogs.ugidotnet.org/DanBlog/archive/2007/08/16/87832.aspx#feedback http://blogs.ugidotnet.org/DanBlog/comments/commentRss/87832.aspx http://blogs.ugidotnet.org/DanBlog/services/trackbacks/87832.aspx NHibernate quick start http://blogs.ugidotnet.org/DanBlog/archive/2007/08/16/87831.aspx <p>- installare, se necessario, NH</p> <p>- aggiungere il progetto Persistence alla solution</p> <p>- aggiungere a Persistence il riferimento a NHibernate.dll e ai progetti della solution necessari (BusinessObjetcts, ...)</p> <p>- aggiungere al file di configurazione del progetto che verrà avviato la sezione per NH:</p> <p>&lt;configSections&gt; <br /> &lt;section name="nhibernate" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /&gt; <br /> &lt;/configSections&gt; <br /> &lt;nhibernate&gt; <br /> &lt;add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" /&gt; <br /> &lt;add key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" /&gt; <br /> &lt;add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2005Dialect" /&gt; <br /> &lt;add key="hibernate.connection.connection_string" value="Server=localhost; Integrated Security=SSPI; Database=ComLog;" /&gt; <br /> &lt;add key="hibernate.default_schema" value="dbo" /&gt; <br /> <br /> &lt;!-- General --&gt; <br /> &lt;add key="hibernate.use_proxy_validator" value="true"/&gt; <br /> <br /> &lt;!-- SQL Generation --&gt; <br /> &lt;add key="hibernate.max_fetch_depth" value="2"/&gt; <br /> &lt;add key="hibernate.show_sql" value="false"/&gt; <br /> <br /> &lt;add key="hibernate.connection.release_mode" value="on_close" /&gt; <br /> <br /> <br /> &lt;!-- Reflection Optimizer: null | lcg | codedom --&gt; <br /> &lt;add key="hibernate.use_reflection_optimizer" value="true"/&gt; <br /> &lt;add key="hibernate.bytecode.provider" value="lcg"/&gt; <br /> <br /> &lt;/nhibernate&gt;</p> <p>- aggiungere a Persistence la classe SessionHelper, che si occuperà di istanziare le sessioni dalla factory</p> <p>Esempio:</p> <p>using System.Reflection; <br /> using NHibernate; <br /> using NHibernate.Cfg; <br /> <br /> namespace Persistence <br /> { <br /> public class SessionHelper <br /> { <br /> private static ISessionFactory factory; <br /> <br /> static SessionHelper() <br /> { <br /> Configuration cfg = new Configuration(); <br /> cfg.AddAssembly(Assembly.GetExecutingAssembly()); <br /> factory = cfg.BuildSessionFactory(); <br /> } <br /> <br /> public static ISession GetSession() <br /> { <br /> return factory.OpenSession(); <br /> } <br /> <br /> public static ISession GetSession(IInterceptor interceptor) <br /> { <br /> return factory.OpenSession(interceptor); <br /> }</p> <p>- aggiungere i file di mapping di NH col nome classe.hbm.xml; esempio:</p> <p><font size="2">&lt;?xml version="1.0" encoding="utf-8" ?&gt; <br /> &lt;hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" <br /> assembly="BusinnessObjects" <br /> namespace="BusinnessObjects"&gt; <br /> &lt;class name="Group" table="Groups" lazy="false"&gt; <br /> &lt;id name="Id"&gt; <br /> &lt;generator class="guid" /&gt; <br /> &lt;/id&gt; <br /> &lt;property name ="Name" /&gt; <br /> <br /> &lt;/class&gt; <br /> &lt;/hibernate-mapping&gt;</font></p> <p><font size="2">- ricordati di impostare i file di mapping come Embedded Resource</font></p> <p><font size="2">A questo punto </font>è possibile usare la session per salvare/caricare oggetti:</p> <p>ISession session = SessionHelper.GetSession(); <br /> using (session) <br /> { <br /> Group group = new Group(); <br /> group.Name = "gruppo test"; <br /> group.Id = new Guid(); <br /> session.SaveOrUpdate(group); <br /> session.Flush();<br /> }</p> <p>Per migliorare l'architettura aggiungere provider e manager:</p> <p>- aggiungere a Persistence la classe generica del ProviderNH; ad esempio:</p> <p>using System; <br /> using System.Collections.Generic; <br /> using System.Reflection; <br /> using NHibernate; <br /> using NHibernate.Transform; <br /> <br /> namespace Persistence <br /> { <br /> public class NHibernateProvider&lt;T&gt; : IDisposable <br /> { <br /> private ISession _session; <br /> //public event EventHandler&lt;BeforeCommitEventArgs&gt; BeforeCommit; <br /> <br /> protected ISession Session <br /> { <br /> get { return _session; } <br /> set { _session = value; } <br /> } <br /> <br /> public NHibernateProvider() <br /> { <br /> Session = SessionHelper.GetSession(); <br /> } <br /> <br /> <br /> public T LoadById(Int32 id) <br /> { <br /> return Session.Load&lt;T&gt;(id); <br /> } <br /> <br /> public T LoadById(String id) <br /> { <br /> return Session.Load&lt;T&gt;(id); <br /> } <br /> <br /> public IList&lt;T&gt; LoadAll() <br /> { <br /> return LoadAll(String.Empty, true); <br /> } <br /> <br /> public IList&lt;T&gt; LoadAll(String associationPath, Boolean lazy) <br /> { <br /> ICriteria criteria = Session.CreateCriteria(typeof(T)); <br /> if (lazy) <br /> { <br /> return criteria.List&lt;T&gt;(); <br /> } <br /> else <br /> { <br /> return criteria.SetFetchMode(associationPath, FetchMode.Join) <br /> .SetResultTransformer(new DistinctRootEntityResultTransformer()).List&lt;T&gt;(); <br /> } <br /> } <br /> <br /> <br /> public IList&lt;T&gt; LoadBy(String hql) <br /> { <br /> return Session.CreateQuery(hql).List&lt;T&gt;(); <br /> } <br /> <br /> public void Save(T value) <br /> { <br /> ITransaction tx = Session.BeginTransaction(); <br /> Session.SaveOrUpdate(value); <br /> <br /> //OnBeforeCommit(value); <br /> <br /> try <br /> { <br /> tx.Commit(); // Fa commit e flush <br /> } <br /> catch (Exception ex) <br /> { <br /> tx.Rollback(); <br /> //Logger.Error(this, MethodInfo.GetCurrentMethod().Name, ex); <br /> throw; <br /> } <br /> } <br /> <br /> public void SaveNew(T value) <br /> { <br /> ITransaction tx = Session.BeginTransaction(); <br /> Session.Save(value); <br /> <br /> //OnBeforeCommit(value); <br /> <br /> try <br /> { <br /> tx.Commit(); // Fa commit e flush <br /> } <br /> catch (Exception ex) <br /> { <br /> tx.Rollback(); <br /> //Logger.Error(this, MethodInfo.GetCurrentMethod().Name, ex); <br /> throw; <br /> } <br /> } <br /> <br /> //private void OnBeforeCommit(T value) <br /> //{ <br /> // if (BeforeCommit != null) <br /> // BeforeCommit(this, new BeforeCommitEventArgs(value)); <br /> //} <br /> <br /> <br /> public void Delete(T value) <br /> { <br /> Session.Delete(value); <br /> Session.Flush(); <br /> } <br /> <br /> <br /> public void Dispose() <br /> { <br /> Session.Close(); <br /> Session.Dispose(); <br /> } <br /> } <br /> }</p> <p>- aggiungere i provider specifici per i vari business objects</p> <p>- aggiungere i manager che utilizzano i provider specifici</p><img src="http://blogs.ugidotnet.org/DanBlog/aggbug/87831.aspx" width="1" height="1" /> Daniele Armanasco http://blogs.ugidotnet.org/DanBlog/archive/2007/08/16/87831.aspx Thu, 16 Aug 2007 02:37:21 GMT http://blogs.ugidotnet.org/DanBlog/archive/2007/08/16/87831.aspx#feedback 1629 http://blogs.ugidotnet.org/DanBlog/comments/commentRss/87831.aspx http://blogs.ugidotnet.org/DanBlog/services/trackbacks/87831.aspx NHibernate - file di configurazione http://blogs.ugidotnet.org/DanBlog/archive/2007/07/18/86081.aspx <p>Situazione: </p> <p>i file di mapping e le classi helper di NH stannno nel progetto Persistence a cui il progetto Web ed altri progetti fanno riferimento. Essendo diversi i progetti che utilizzano Persistence non si vuole duplicare la configurazione di NH per ognuno di essi, per cui si è deciso di non inserirla nel web.config ma in un file di configurazione presente in Persistence.</p> <p>Pb1: il file di configurazione, normalmente, non segue il file assembly (che in fase di compilazione viene copiato nella directory del progetto "chiamante").</p> <p>Soluzione: imposto Copy to output directory = copy always per il file di configurazione.</p> <p> </p> <p>Pb2: la sessionFactory deve essere creata leggendo la configurazione da un file diverso da web.config.</p> <p>Quasi-soluzione1: è possibile specificare un nome arbitrario di file da cui la session factory deve attingere la configurazione così:</p> <p>sessionFactory = new Configuration().Configure("C:\\...path...\\nhibernate.config").BuildSessionFactory();</p> <p>Pb: se utilizzo un percorso relativo cerca il file in System32 e non nella cartella di Output. Soluzione?</p> <p>Soluzione2: chiamo il file di configurazione con il nome standard gestito da NH, cioè hibernate.cfg.xml; in questo caso il file viene cercato nella cartella di output e il tutto funziona.</p><img src="http://blogs.ugidotnet.org/DanBlog/aggbug/86081.aspx" width="1" height="1" /> Daniele Armanasco http://blogs.ugidotnet.org/DanBlog/archive/2007/07/18/86081.aspx Wed, 18 Jul 2007 15:51:00 GMT http://blogs.ugidotnet.org/DanBlog/archive/2007/07/18/86081.aspx#feedback 1 http://blogs.ugidotnet.org/DanBlog/comments/commentRss/86081.aspx http://blogs.ugidotnet.org/DanBlog/services/trackbacks/86081.aspx NHibernate: formattare le date in HQL http://blogs.ugidotnet.org/DanBlog/archive/2007/05/18/78519.aspx <p>Il formato più conveniente è:</p> <font size="2"> <p>day.ToString(</p> </font><font color="#a31515" size="2">"yyyy/MM/dd"</font><font size="2">);</font><img src="http://blogs.ugidotnet.org/DanBlog/aggbug/78519.aspx" width="1" height="1" /> Daniele Armanasco http://blogs.ugidotnet.org/DanBlog/archive/2007/05/18/78519.aspx Fri, 18 May 2007 01:03:00 GMT http://blogs.ugidotnet.org/DanBlog/archive/2007/05/18/78519.aspx#feedback 1 http://blogs.ugidotnet.org/DanBlog/comments/commentRss/78519.aspx http://blogs.ugidotnet.org/DanBlog/services/trackbacks/78519.aspx NHibernate: eccezione "a different object with the same identifier value was already associated with the session" - SaveOrUpdateCopy http://blogs.ugidotnet.org/DanBlog/archive/2007/04/23/76267.aspx Non ho ancora avuto il tempo di comprendere a fondo la questione, però quando utilizzavo SaveOrUpdate per aggiornare un oggetto già oggetto dello stesso metodo un paio di volte, ottenevo l'eccezione indicata e il record nel db non veniva aggiornata con il Flush successivo. Usando invece SaveOrUpdateCopy, se l'oggetto è già presente nel contesto di persistenza, non viene generata l'eccezione ma viene aggiornato l'oggetto presente (ciò che io pensavo facesse SaveOrUpdate; a questo punto cosa fa SaveOrUpdate? E Update?)<img src="http://blogs.ugidotnet.org/DanBlog/aggbug/76267.aspx" width="1" height="1" /> Daniele Armanasco http://blogs.ugidotnet.org/DanBlog/archive/2007/04/23/76267.aspx Mon, 23 Apr 2007 01:39:00 GMT http://blogs.ugidotnet.org/DanBlog/archive/2007/04/23/76267.aspx#feedback 2 http://blogs.ugidotnet.org/DanBlog/comments/commentRss/76267.aspx http://blogs.ugidotnet.org/DanBlog/services/trackbacks/76267.aspx