agosto 2007 Entries

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,

è 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.

- installare, se necessario, NH

- aggiungere il progetto Persistence alla solution

- aggiungere a Persistence il riferimento a NHibernate.dll e ai progetti della solution necessari (BusinessObjetcts, ...)

- aggiungere al file di configurazione del progetto che verrà avviato la sezione per NH:

<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.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" />
<add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2005Dialect" />
<add key="hibernate.connection.connection_string" value="Server=localhost; Integrated Security=SSPI; Database=ComLog;" />
<add key="hibernate.default_schema" value="dbo" />

<!-- General -->
<add key="hibernate.use_proxy_validator" value="true"/>

<!-- SQL Generation -->
<add key="hibernate.max_fetch_depth" value="2"/>
<add key="hibernate.show_sql" value="false"/>

<add key="hibernate.connection.release_mode" value="on_close" />


<!-- Reflection Optimizer: null | lcg | codedom -->
<add key="hibernate.use_reflection_optimizer" value="true"/>
<add key="hibernate.bytecode.provider" value="lcg"/>

</nhibernate>

- aggiungere a Persistence la classe SessionHelper, che si occuperà di istanziare le sessioni dalla factory

Esempio:

using System.Reflection;
using NHibernate;
using NHibernate.Cfg;

namespace Persistence
{
public class SessionHelper
{
private static ISessionFactory factory;

static SessionHelper()
{
Configuration cfg = new Configuration();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
factory = cfg.BuildSessionFactory();
}

public static ISession GetSession()
{
return factory.OpenSession();
}

public static ISession GetSession(IInterceptor interceptor)
{
return factory.OpenSession(interceptor);
}

- aggiungere i file di mapping di NH col nome classe.hbm.xml; esempio:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="BusinnessObjects"
namespace="BusinnessObjects">
<class name="Group" table="Groups" lazy="false">
<id name="Id">
<generator class="guid" />
</id>
<property name ="Name" />

</class>
</hibernate-mapping>

- ricordati di impostare i file di mapping come Embedded Resource

A questo punto è possibile usare la session per salvare/caricare oggetti:

ISession session = SessionHelper.GetSession();
using (session)
{
Group group = new Group();
group.Name = "gruppo test";
group.Id = new Guid();
session.SaveOrUpdate(group);
session.Flush();
}

Per migliorare l'architettura aggiungere provider e manager:

- aggiungere a Persistence la classe generica del ProviderNH; ad esempio:

using System;
using System.Collections.Generic;
using System.Reflection;
using NHibernate;
using NHibernate.Transform;

namespace Persistence
{
public class NHibernateProvider<T> : IDisposable
{
private ISession _session;
//public event EventHandler<BeforeCommitEventArgs> BeforeCommit;

protected ISession Session
{
get { return _session; }
set { _session = value; }
}

public NHibernateProvider()
{
Session = SessionHelper.GetSession();
}


public T LoadById(Int32 id)
{
return Session.Load<T>(id);
}

public T LoadById(String id)
{
return Session.Load<T>(id);
}

public IList<T> LoadAll()
{
return LoadAll(String.Empty, true);
}

public IList<T> LoadAll(String associationPath, Boolean lazy)
{
ICriteria criteria = Session.CreateCriteria(typeof(T));
if (lazy)
{
return criteria.List<T>();
}
else
{
return criteria.SetFetchMode(associationPath, FetchMode.Join)
.SetResultTransformer(new DistinctRootEntityResultTransformer()).List<T>();
}
}


public IList<T> LoadBy(String hql)
{
return Session.CreateQuery(hql).List<T>();
}

public void Save(T value)
{
ITransaction tx = Session.BeginTransaction();
Session.SaveOrUpdate(value);

//OnBeforeCommit(value);

try
{
tx.Commit(); // Fa commit e flush
}
catch (Exception ex)
{
tx.Rollback();
//Logger.Error(this, MethodInfo.GetCurrentMethod().Name, ex);
throw;
}
}

public void SaveNew(T value)
{
ITransaction tx = Session.BeginTransaction();
Session.Save(value);

//OnBeforeCommit(value);

try
{
tx.Commit(); // Fa commit e flush
}
catch (Exception ex)
{
tx.Rollback();
//Logger.Error(this, MethodInfo.GetCurrentMethod().Name, ex);
throw;
}
}

//private void OnBeforeCommit(T value)
//{
// if (BeforeCommit != null)
// BeforeCommit(this, new BeforeCommitEventArgs(value));
//}


public void Delete(T value)
{
Session.Delete(value);
Session.Flush();
}


public void Dispose()
{
Session.Close();
Session.Dispose();
}
}
}

- aggiungere i provider specifici per i vari business objects

- aggiungere i manager che utilizzano i provider specifici

Utilizzare NUnit in un progetto:

- installare, se necessario, il programma;

- aggiungere un progetto di test alla solution; in questo progetto:

- aggiungere un riferimento a nunit.framework.dll

- aggiungere le classi di test (TestFixture; DEVONO ESSERE PUBLIC) e i test veri e propri (DEVONO RITORNARE VOID E NON DEVONO AVERE PARAMETRI):

using NUnit.Framework;
using BusinnessObjects;

namespace Test
{
[TestFixture]
public class UserTest
{
[Test]
public void DefaultUserAreNotDestination()
{
User user = new User();
user.Name = "Pinco Pallino";

Assert.AreEqual(false, user.IsDestination);
}

- avviare il programma di esecuzione dei test (nunit-gui.exe) e in esso:

- definire un nuovo progetto di test e salvarlo

- aggiungere al progetto di NUnit l'assembly del progetto di test presente nella solution

Non resta che compilare la solution ed eseguire i test (ad ogni compilazione il progetto NUnit ricarica i test automaticamente).

The ?? operator returns the left-hand operand if it is not null, or else it returns the right operand.

int y = x ?? -1;

oppure

if ((reader.GetAttribute("showheader") ?? String.Empty).ToUpper() == "TRUE")

Aggiungo al progetto il file XML e imposto Build Action = Embedded resource.

Se necessario creo un nuovo file di definizione delle risorse dalle proprietà del progetto.

Nel file di definizione delle risorse aggiungo una risorsa di tipo File.

A run-time recupero il file:

            using System.Resources;

            ...

            ResourceManager rm = new ResourceManager("NomeProgetto.Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly());
            Object file = rm.GetObject("NomeRisorsa");
            String info = file.ToString();

 

Lunedì sera ho imboccato l'autostrada per recarmi da un cliente e, poco dopo, ho notato l'accensione di una spia sul cruscotto della mia nuova Meriva, una spia con una chiave inglese disegnata su un'autovettura ... ahi ahi ahi ... immediatamente ho realizzato che l'auto non accelerava più, nemmeno premendo a tavoletta. Ho raggiunto il primo casello viaggiando sulla corsia di emergenza ai 70 km/h e ho imboccato la tangenziale per ritornare a casa. Giunto ad una piazzola mi sono fermato per consultare il manuale che consigliava di recarsi alla prima autofficina ma, spulciandolo a fondo, diceva anche che a volte per risolvere il problema è sufficiente spegnere e riaccendere l'autovettura; se alla riaccensione la spia non si accende significa che il problema è risolto, e così è stato! Ho quindi potuto riprendere il mio viaggio e il giorno dopo, sentita la concessionaria, come prima cosa mi hanno chiesto: "ha provato a spegnere e riaccendere?". Mi avranno montato Windows CE (Car Embedded)?

Meglio così; se me lo avessero detto prima o il manuale l'avesse evidenziato avrei risparmiato un'oretta e un pò di stress; comunque la prossima volta è la prima cosa che provo!

Contesto: voglio creare un controllo che generi html "puro" a mia completa discrezione.

Quasi-soluz. 1: creo uno user control contenente solo un literal. Creo un metodo di rendering che costruisce la stringa html e la assegna alla proprietà Text del literal. Se non ho bisogno di settare proprietà dal codice che utilizza lo user control posso richiamare il metodo di rendering sul page load. In caso contrario devo dichiarare come public il metodo di rendering e chiamarlo esplicitamente dal codice utilizzatore dopo aver impostato le proprietà necessarie (magari per definire la sorgente dati).

Soluzione 2: sovrascrivo il metodo di rendering che tutti i controlli utilizzano; in tale metodo genero la stringa html. In questo caso non ho bisogno di definire come pubblico il metodo di rendering e non devo chiamarlo esplicitamente. Inoltre non mi serve il literal (lo user control è vuoto); utilizzo l'oggetto output di tipo HtmlTextWriter.

        protected override void Render(HtmlTextWriter output)
        {
            htmlStringBuilder.Append("            ...
            htmlStringBuilder.Append("

");

            output.Write(htmlStringBuilder.ToString());
        }