samedi 6 décembre 2008

QuickStart NHibernate Remix


Un jour, il me prit envie de tester le cadriciel Nhibernate (ORM pour plateforme .NET), je me suis donc dirigé vers le site officiel pour y faire fonctionner le tutoriel « Quickstart » qui était censé me permettre de mettre rapidement le pied à l’étrier. Sans m’en rendre compte, j’allais au devant de quelques déconvenues. Ce tutoriel ne marche pas. Dans un élan d’altruisme j’ai donc décidé de proposer un « Quickstart Nhibernate » de mon cru qui lui fonctionne.

 

L’environnement de développement intégré est le fameux Visual Studio dans son édition professionnelle et dans sa version 2008 service pack 1 (la dernière à ce jour).

La base de données utilisée est MySQL dans sa version 5.1.

La version des binaires d’ NHibernate est la 2.0.1.GA.

Le driver MySQL utilisé est « MySQL Connector .NET 5.2.5 ».

 

 

Lancez Visual Studio. Allez dans Fichier >Nouveau > Projet > Visual C# > Web. Sélectionnez « Application Web ASP.NET », appelez votre  application QuickStart.

Dans l’explorateur de solution vous pouvez voir votre projet QuickStart, en faisant un clic droit sur  « References »  allez dans l’onglet Parcourir et ajoutez la dll NHibernate.dll (présente dans le répertoire « bin/net-2.0 » du dossier qui contient NHibernate. Ajouter aussi en référence la dll MySQL.Data.dll présente dans le dossier « binaries/.NET 2.0 » de MySQL Connector .NET. Sélectionnez la dll MySQL.Data.dll dans « References », effectuez un clic droit, cliquez sur « Propriétés », mettez « Copie Locale » à « True ».

Modifions maintenant le fichier Web.config, il doit ressembler à ça :

 

 

<?xml version="1.0" encoding="utf-8"?>

 

<configuration>

 

 

  <configSections>

    <sectionGroup name="system.web.extensions" type="System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">

      <sectionGroup name="scripting" type="System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">

        <section name="scriptResourceHandler" type="System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication"/>

        <sectionGroup name="webServices" type="System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">

          <section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="Everywhere" />

          <section name="profileService" type="System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />

          <section name="authenticationService" type="System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />

          <section name="roleService" type="System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" allowDefinition="MachineToApplication" />

        </sectionGroup>

      </sectionGroup>

    </sectionGroup>

    <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"/>

  </configSections>

 

  <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">

    <session-factory name="NHibernate.QuickStart">

      <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>

      <property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>

      <property name="connection.connection_string">

        Database=quickstart;Data Source=127.0.0.1;User Id=root;Password=root

      </property>

      <property name="dialect">NHibernate.Dialect.MySQLDialect</property>

    </session-factory>

 

  </hibernate-configuration>

  <appSettings/>

  <connectionStrings/>

 

  <system.web>

    <!--

            Définissez compilation debug="true" pour insérer des symboles

            de débogage dans la page compilée. Comme ceci

            affecte les performances, définissez cette valeur à true uniquement

            lors du développement.

        -->

    <compilation debug="true">

 

      <assemblies>

        <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>

        <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>

        <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

        <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>

      </assemblies>

 

    </compilation>

    <!--

            La section <authentication> permet la configuration

            du mode d'authentification de sécurité utilisé par

            ASP.NET pour identifier un utilisateur entrant.

        -->

    <authentication mode="Windows" />

    <!--

            La section <customErrors> permet de configurer

            les actions à exécuter si/quand une erreur non gérée se produit

            lors de l'exécution d'une demande. Plus précisément,

            elle permet aux développeurs de configurer les pages d'erreur html

            pour qu'elles s'affichent à la place d'une trace de la pile d'erreur.

 

        <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">

            <error statusCode="403" redirect="NoAccess.htm" />

            <error statusCode="404" redirect="FileNotFound.htm" />

        </customErrors>

        -->

 

    <pages>

      <controls>

        <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

        <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

      </controls>

    </pages>

 

    <httpHandlers>

      <remove verb="*" path="*.asmx"/>

      <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

      <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

      <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>

    </httpHandlers>

    <httpModules>

      <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

    </httpModules>

 

  </system.web>

 

  <system.codedom>

    <compilers>

      <compiler language="c#;cs;csharp" extension=".cs" warningLevel="4"

                type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">

        <providerOption name="CompilerVersion" value="v3.5"/>

        <providerOption name="WarnAsError" value="false"/>

      </compiler>

    </compilers>

  </system.codedom>

 

  <!--

        La section system.webServer est requise pour exécuter ASP.NET AJAX sur Internet

        Information Services 7.0.  Elle n'est pas nécessaire pour les versions précédentes d'IIS.

    -->

  <system.webServer>

    <validation validateIntegratedModeConfiguration="false"/>

    <modules>

      <remove name="ScriptModule" />

      <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

    </modules>

    <handlers>

      <remove name="WebServiceHandlerFactory-Integrated"/>

      <remove name="ScriptHandlerFactory" />

      <remove name="ScriptHandlerFactoryAppServices" />

      <remove name="ScriptResource" />

      <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode"

           type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

      <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode"

           type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>

      <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />

    </handlers>

  </system.webServer>

 

  <runtime>

    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

      <dependentAssembly>

        <assemblyIdentity name="System.Web.Extensions" publicKeyToken="31bf3856ad364e35"/>

        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>

      </dependentAssembly>

      <dependentAssembly>

        <assemblyIdentity name="System.Web.Extensions.Design" publicKeyToken="31bf3856ad364e35"/>

        <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="3.5.0.0"/>

      </dependentAssembly>

    </assemblyBinding>

  </runtime>

 

</configuration>


Comme vous avez pu le constater l’ «user id » et le « password » de MySQL sont root et root, adapatez les aux identifiants qui vous permettent de vous connecter à votre base données.

Ajouter un nouvel élément à votre projet, une classe que vous appellerez « Cat » complétez cette classe comme suit :

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

 

namespace QuickStart

{

    public class Cat

    {

        private long id;

        private string name;

        private char sex;

        private float weight;

 

        public Cat()

        {

        }

 

 

        public virtual long Id

        {

            get { return id; }

            set { id = value; }

        }

 

 

        public virtual string Name

        {

            get { return name; }

            set { name = value; }

        }

 

 

        public virtual char Sex

        {

            get { return sex; }

            set { sex = value; }

        }

 

 

        public virtual float Weight

        {

            get { return weight; }

            set { weight = value; }

        }

 

    }

}

 

 

Cela ne vous aura pas échappé le champ id est içi un long et non pas un string, en effet pour MySQL le champ id doit être obligatoirement un entier.

 

Créons  le fichier de mapping xml de la classe Cat : ajoutez un nouvel élément au projet, sélectionnez « fichier xml » appelez ce fichier Cat.hbm.xml. Compléter de fichier comme suit :

 

<?xml version="1.0" encoding="utf-8" ?>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"

    namespace="QuickStart" assembly="QuickStart">

 

  <class name="Cat" table="Cat">

 

    <!-- A 32 hex character is our surrogate key. It's automatically

            generated by NHibernate with the UUID pattern. -->

    <id name="Id">

      <column name="id"  not-null="true"/>

      <generator class="native" />

    </id>

 

    <!-- A cat has to have a name, but it shouldn' be too long. -->

    <property name="Name">

      <column name="Name" length="16" not-null="true" />

    </property>

    <property name="Sex" />

    <property name="Weight" />

  </class>

 

</hibernate-mapping>

 

 

Ajoutez la classe NHibernateHelper à votre projet, complétez la comme suit :

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using NHibernate;

using NHibernate.Cfg;

 

namespace QuickStart

{

    public sealed class NHibernateHelper

    {

        private const string CurrentSessionKey = "nhibernate.current_session";

        private static readonly ISessionFactory sessionFactory;

 

        static NHibernateHelper()

        {

            //sessionFactory = new Configuration().Configure().BuildSessionFactory();

            NHibernate.Cfg.Configuration cfg = new Configuration();

            cfg.Configure();

            string basePath = System.Web.HttpContext.Current.Server.MapPath(@"/");

            cfg.AddXmlFile(basePath + "Cat.hbm.xml");

            sessionFactory = cfg.BuildSessionFactory();

        }

 

        public static ISession GetCurrentSession()

        {

            HttpContext context = HttpContext.Current;

            ISession currentSession = context.Items[CurrentSessionKey] as ISession;

 

            if (currentSession == null)

            {

                currentSession = sessionFactory.OpenSession();

                context.Items[CurrentSessionKey] = currentSession;

 

            }

 

            return currentSession;

        }

 

        public static void CloseSession()

        {

            HttpContext context = HttpContext.Current;

            ISession currentSession = context.Items[CurrentSessionKey] as ISession;

 

            if (currentSession == null)

            {

                // No current session

                return;

            }

 

            currentSession.Close();

            context.Items.Remove(CurrentSessionKey);

        }

 

        public static void CloseSessionFactory()

        {

            if (sessionFactory != null)

            {

                sessionFactory.Close();

            }

        }

 

    }

}

 

 

Créez votre base de donné « quickstart » dans MySQL, rajoutez y la table « Cat » à l’aide de la commande suivante :

 

create table cat (id INT NOT NULL PRIMARY KEY auto_increment,name VARCHAR

(16), sex VARCHAR(1), weight FLOAT);

 

La table Cat ressemblera à ceci :

 

+--------+-------------+------+-----+---------+------- -----------+

| Field  | Type            | Null | Key | Default | Extra                     |

+--------+-------------+------+-----+---------+--------------------+

| id          | int(11)       | NO   |       | NULL   | auto_increment |

| name    | varchar(16) | NO  |       | NULL  |                              |

| sex       | varchar(1)  | YES  |       | NULL |                               |

| weight  | float          | YES  |       | NULL  |                   |

+--------+-------------+------+-----+---------+---------------------+

 

Editions maintenant le fichier Default.aspx.cs comme suit :

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using NHibernate;

 

namespace QuickStart

{

    public partial class _Default : System.Web.UI.Page

    {

        protected void Page_Load(object sender, EventArgs e)

        {

            ISession session = NHibernateHelper.GetCurrentSession();

 

            ITransaction tx = session.BeginTransaction();

 

            Cat princess = new Cat();

            princess.Name = "Princess";

            princess.Sex = 'F';

            princess.Weight = 7.4f;

 

            session.Save(princess);

            tx.Commit();

 

 

            tx = session.BeginTransaction();

            IQuery query = session.CreateQuery("select c from Cat as c where c.Sex = :sex");

            query.SetCharacter("sex", 'F');

            foreach (Cat cat in query.Enumerable())

            {

                Console.Out.WriteLine("Female Cat: " + cat.Name);

            }

 

            tx.Commit();

 

            NHibernateHelper.CloseSession();

        }

    }

}

 

 

Voila, vous n’avez plus qu’a lancer votre application : clic droit sur votre projet dans l’explorateur de solution > Déboguer > Démarrer une nouvelle instance.

Aucun commentaire: