Tag: nhibernate

Bonne résolutions 2011 : quelques mises à jour de nos outils sont à prévoir

Posted by – January 6, 2011

Quelques sorties de nouvelles versions, programmons vite les mises à jour :

  • ORM : NHibernate 3.0 : Linq, Lazy property, memcached, QueryOver API pour les requêtes Criteria, un billet suivra sur certaines des nouveautés,
  • IoC : Castle Windows 2.5.2 : .NET 4.0, réduction à seulement 2 assembly (au lieu de 4), et d’autres améliorations,
  • Wiki : dokuWiki Anteater : améliorations de l’API XmlRPC (ajout de la recherche plein texte dans les pages du Wiki), recherche sur le Wiki plus pertinente,
  • il me plait bien ce moteur de rendu Razor d’ASP.NET MVC 3 R2

Y’a plus qu’à.

NHibernate et les propriétés magiques

Posted by – March 14, 2010

Préambule

La différence entre la théorie et la pratique ? en théorie, il n’y en a pas, en pratique, si.

Le monde du développement est loin d’être un monde idéal, dans la réalité, nous rencontrons souvent des situations particulières auxquelles il faut faire face. Un framework, en plus de répondre aux besoins les plus généraux, se doit également de fournir des solutions de contournements, des “astuces de programmation” diront certains.

Dans ce court billet, nous allons parler de 2 fonctionnalités de NHibernate sur les propriétés lorsque notre modèle ou le contexte ne répond pas exactement à l’idéal que l’on devrait avoir en termes d’architecture.

More

NHModeler : DSL de génération de code à base d’Oslo / langage M, rien ne se perd, rien ne se crée, tout se transforme en info

Posted by – October 7, 2009

Flex et Bison

Je me souviens dans ma jeunesse (il y a très peu de temps donc), dans la boite où j’ai commencé mon activité pro, on développait des services de messageries roses télématiques à 1,23 Frs /mn (voire le double en trichant un peu). Vous savez l’Internet français, qu’on appelait Minitel sur le réseau X25 de Transpac (CA du minitel en 2007 : 100 millions €, à peine imaginable)

Le moteur Opsion que nous utilisions générait du C, et il fallait donc écrire du C pour nos services. A l’époque, point de bases de données, mais des fichiers indexés au format C-ISAM. A chaque entité, il fallait écrire la génération de l’index, tout un tas de petites choses et surtout des fonctions de recherche sur la structure de données (à l’octet près…) (par catégorie, par nom, …) en utilisant l’API C-ISAM, ce qui était assez fastidieux, et surtout courageux.

More

NHibernate : pagination, tri et accessoirement Future

Posted by – August 12, 2009

Préambule

NHibernate vient de passer en version 2.1, avec son lot de nouvelles fonctionnalités.

Lors d’un développement Web, il arrive couramment de mettre en place de la pagination et du tri sur les pages pour afficher les N éléments d’une série. Jusqu’à quelques centaines d’objets, cette pagination peut aisément s’effectuer côté couche Web, en coupant et triant une liste d’objets : on pourra s’aider de Linq to Objects pour ça, avec par exemple du Skip et du Take et des orderby. Le problème de cette technique est de ramener l’ensemble de sa sélection puis de la filtrer dans la couche de plus niveau, ce qui peut être assez désastreux lorsque l’on vient à avoir des collections de milliers d’objets : cela en devient très lent, et pour nos utilisateurs adorés, on se doit de trouver une solution.

Dans ce cas, une solution est de s’orienter sur une pagination côté base de données, qui s’avère bien plus efficace car ne sont ramenés uniquement les objets à afficher sur la page : si la pagination est de 50 éléments par page, on ramène 50 objets et non 7 000 pour n’en prendre que 50 si on utilisait la première méthode.

Voyons comment faire simplement en s’appuyant sur NHibernate, le dialect MSSQL 2005 / 2008. On utilisera aussi les Future pour gagner un peu plus en performances.

More

Links #16 : NHibernate II

Posted by – July 25, 2009

C’est l’été avec des mises à jour de versions en perspective.

Links #15 : NHibernate

Posted by – April 21, 2009

  • Ayende nous livre ici une série sur quelques techniques NHibernate, avec exemples à l’appui, passionnant, à découvrir ou à re-découvrir, à bookmarker d’urgence,
  • Fluent NHibernate : cela en excite plus d’un sur twitter ;-) et je peux le comprendre car ça titille aussi mes sens : en plus de vouloir remplacer les hbm, on trouvera l’AutoMapping qui nous évitera peut-être d’oublier des choses dans le fichier de mapping hbm (je me comprends), mais aussi d’avoir des helpers pour des repo génériques (Find, Save, Delete, …), ou d’effectuer des tests en mémoire (vs. DB) , et, originalité, il se compilera à l’aide de Rake (mais il y a tout de même un SLN),
  • Linq to NHibernate : vous permettra d’écrire des lignes du type session.Linq<MyEntite>.Where(x => x.Result && x.Libelle==”tdd”). Il est livré avec NHContrib, ou simplement directement avec ses propres sources, et cela sera beaucoup (beaucoup) moins long à télécharger. Ou bien, prendre l’assembly NHibernate.Linq.dll contenue dans Fluent NHibernate. Il y en a même qui se sont essayés à LinqToNHibernate dans LinqPad.
  • Dans la 2.1, ils vont enfin remplacer Iesi par les HashSet de .NET.

NHibernate : HQL et Criteria

Posted by – November 26, 2008

Introduction

Sous NHibernate, il y a 3 manières d’effectuer des requêtes : SQL natif, HQL, et Criteria. La 1ère méthode est à proscrire, sous peine de perdre l’abstraction avec la base, liée à la syntaxe SQL spécifique à celle-ci. Reste HQL et les Criteria, je me demandais quelle méthode utiliser.

Modèle, mapping et requêtes

Soit le modèle suivant :

assoc-resp.png

pour des raisons certainement très justifiées (legacy & co), j’ai besoin d’avoir un objet pour représenter la table de jointure, et ne retenir que l’entité Association et la table de jointure entre Association et Responsable, on aura les tables suivantes : ASSOC et ASSOCRESP. Donc point de many-to-many ici, mais juste une (sous-)requête à réaliser entre ASSOC et ASSOCRESP.

Au niveau base de données, on trouve le schéma de tables suivant (généré avec la syntaxe SQLite par NHibernate) :

CREATE TABLE ASSOC (  Id  integer,   assoc_code TEXT NOT NULL,   assoc_libelle TEXT NOT NULL,   PRIMARY KEY (Id)) CREATE TABLE ASSOCRESP (  resp_id INTEGER NOT NULL,   assoc_id INTEGER NOT NULL,   PRIMARY KEY (resp_id, assoc_id))

et le mapping suivant :

<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true" >   <class name="AssocConnector.Assoc, AssocConnector" table="ASSOC">     <id name="Id" column="Id" type="System.Int32" access="property">       <generator class="identity"></generator>     </id>     <property name="Code" column="assoc_code" not-null="true" type="System.String" access="property"/>     <property name="Libelle" column="assoc_libelle" not-null="true" type="System.String" access="property"/>     </class> </hibernate-mapping>

une clé composite pour la table de jointure :

<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" auto-import="true" >   <class name="AssocConnector.ResponsableAssoc, AssocConnector" table="ASSOCRESP">     <composite-id>       <key-property name="Responsable" column="resp_id" type="System.Int32" access="property"/>       <key-property name="Assoc" column="assoc_id" type="System.Int32" access="property"/>     </composite-id>   </class> </hibernate-mapping>

Un test (la méthode GetAssocForAResponsable_ShouldReturn_2Assoc nous intéresse) qui utilise les 2 méthodes : HQL et Criteria : renvoie pour une responsable (id) la liste des associations dont il est responsable. Pour l’occasion (et parce qu’on est à fond), on va aussi utiliser les indicateurs (stats.) que permet la version 2 de NHibernate, pour les tests, ça pourrait servir, le code ici est à titre de démonstration des stats (stats + le Delete).

[Test] public void GetAssocForAResponsable_ShouldReturn_2Assoc() { // requête API Criteria var assocCriteria = DetachedCriteria.For<ResponsableAssoc>()        .SetProjection(Projections.Distinct(Projections.Property("Assoc")))        .Add(Restrictions.Eq("Responsable", 1972)); var lassoc1 = session.CreateCriteria(typeof(Assoc), "assoc")        .Add(Subqueries.PropertyIn("Id", assocCriteria)).List();   // requete HQL IQuery q = session.CreateQuery(@"FROM Assoc assoc WHERE assoc.Id IN     (SELECT ra.Assoc FROM ResponsableAssoc ra       WHERE ra.Responsable = :respid)"); var lassoc2 = q.SetParameter("respid", 1972).List();   _displayStats();   Assert.AreEqual(2, lassoc1.Count); Assert.AreEqual(2, lassoc2.Count);   GlobalStats.Clear();   session.BeginTransaction(); session.Delete("from ResponsableAssoc ra where ra.Responsable = :respid", 1972, NHibernateUtil.Int32); session.Transaction.Commit();   _displayStats(); }   [TestFixtureSetUp] public void initall() {     InitalizeSessionFactory(new List<string> {"AssocImpl"}); }   [SetUp] public void init() {     session = CreateSession();       _create_3Assoc();     _create_3Responsables_for_1Assoc(2);     _create_3Responsables_for_1Assoc(3); }   [TearDown] public void end() {     session.Dispose(); }   private IStatistics GlobalStats {     get { return session.SessionFactory.Statistics; } }   private void _displayStats() {     Console.WriteLine("Statistiques NHibernate");     Console.WriteLine("Insert : {0}", GlobalStats.EntityInsertCount);     Console.WriteLine("Delete : {0}", GlobalStats.EntityDeleteCount);     Console.WriteLine("Fetch : {0}", GlobalStats.EntityFetchCount);     Console.WriteLine("Load : {0}", GlobalStats.EntityLoadCount);     Console.WriteLine("Update : {0}", GlobalStats.EntityUpdateCount); } private List<Assoc> _create_3Assoc() {     var assocs = new List<Assoc>                    {                        new Assoc {Code = "A01", Libelle = "Association pour la liberté du NET"},                        new Assoc {Code = "A9078", Libelle = "Association des chiens errants"},                        new Assoc {Code = "A4503", Libelle = "Association des geeks"}                    };     foreach (var asso in assocs)         session.Save(asso);     session.Flush();     foreach (var asso in assocs)         session.Evict(asso);       return assocs; }   private List<ResponsableAssoc> _create_3Responsables_for_1Assoc(int associd) {     var responsableAssocs = new List<ResponsableAssoc>                    {                        new ResponsableAssoc {Assoc = associd, Responsable = 1972},                        new ResponsableAssoc {Assoc = associd, Responsable = 1976},                        new ResponsableAssoc {Assoc = associd, Responsable = 1999}                    };     foreach (var resp in responsableAssocs)         session.Save(resp);     session.Flush();     foreach (var resp in responsableAssocs)         session.Evict(resp);       return responsableAssocs; }

La requête Criteria sera traduite par NHibernate par :

SELECT this_.Id AS Id0_0_, this_.assoc_code AS assoc2_0_0_, this_.assoc_libelle AS assoc3_0_0_ FROM ASSOC this_ WHERE this_.Id IN (SELECT DISTINCT this_0_.assoc_id AS y0_ FROM ASSOCRESP this_0_ WHERE this_0_.resp_id = @p0); @p0 = '1972'

La requête HQL par :

SELECT assoc0_.Id AS Id0_, assoc0_.assoc_code AS assoc2_0_, assoc0_.assoc_libelle AS assoc3_0_ FROM ASSOC assoc0_ WHERE (assoc0_.Id IN(SELECT responsabl1_.assoc_id FROM ASSOCRESP responsabl1_ WHERE (responsabl1_.resp_id=@p0 ))); @p0 = '1972'

Trace complet du test :

 NHibernate: INSERT INTO ASSOC (assoc_code, assoc_libelle) VALUES (@p0, @p1); select last_insert_rowid(); @p0 = 'A01', @p1 = 'Association pour la liberté du NET' NHibernate: INSERT INTO ASSOC (assoc_code, assoc_libelle) VALUES (@p0, @p1); select last_insert_rowid(); @p0 = 'A9078', @p1 = 'Association des chiens errants' NHibernate: INSERT INTO ASSOC (assoc_code, assoc_libelle) VALUES (@p0, @p1); select last_insert_rowid(); @p0 = 'A4503', @p1 = 'Association des geeks' NHibernate: INSERT INTO ASSOCRESP (resp_id, assoc_id) VALUES (@p0, @p1); @p0 = '1972', @p1 = '2' NHibernate: INSERT INTO ASSOCRESP (resp_id, assoc_id) VALUES (@p0, @p1); @p0 = '1976', @p1 = '2' NHibernate: INSERT INTO ASSOCRESP (resp_id, assoc_id) VALUES (@p0, @p1); @p0 = '1999', @p1 = '2' NHibernate: INSERT INTO ASSOCRESP (resp_id, assoc_id) VALUES (@p0, @p1); @p0 = '1972', @p1 = '3' NHibernate: INSERT INTO ASSOCRESP (resp_id, assoc_id) VALUES (@p0, @p1); @p0 = '1976', @p1 = '3' NHibernate: INSERT INTO ASSOCRESP (resp_id, assoc_id) VALUES (@p0, @p1); @p0 = '1999', @p1 = '3' NHibernate: SELECT this_.Id as Id0_0_, this_.assoc_code as assoc2_0_0_, this_.assoc_libelle as assoc3_0_0_ FROM ASSOC this_ WHERE this_.Id in (SELECT distinct this_0_.assoc_id as y0_ FROM ASSOCRESP this_0_ WHERE this_0_.resp_id = @p0); @p0 = '1972' NHibernate: select assoc0_.Id as Id0_, assoc0_.assoc_code as assoc2_0_, assoc0_.assoc_libelle as assoc3_0_ from ASSOC assoc0_ where (assoc0_.Id IN(select responsabl1_.assoc_id from ASSOCRESP responsabl1_ where (responsabl1_.resp_id=@p0 ))); @p0 = '1972' Statistiques NHibernate Insert : 9 Delete : 0 Fetch : 0 Load : 2 Update : 0 NHibernate: select responsabl0_.resp_id as resp1_1_, responsabl0_.assoc_id as assoc2_1_ from ASSOCRESP responsabl0_ where (responsabl0_.resp_id=@p0 ); @p0 = '1972' NHibernate: DELETE FROM ASSOCRESP WHERE resp_id = @p0 AND assoc_id = @p1; @p0 = '1972', @p1 = '2' NHibernate: DELETE FROM ASSOCRESP WHERE resp_id = @p0 AND assoc_id = @p1; @p0 = '1972', @p1 = '3' Statistiques NHibernate Insert : 0 Delete : 2 Fetch : 0 Load : 2 Update : 0 

Conclusion

On peut voir que les 2 méthodes génèrent environ la même requête à Epsilon près.

Mon avis sur les Criteria :

  • API, donc vérifiée à la compilation au niveau de sa construction, mais négligeable, n’utilisons-nous pas le TDD pour le développement ? ;-) ,
  • pour les allergiques du SQL, les Criteria paraissent être un bon compromis,
  • cela reste assez verbeux, beaucoup de lignes pour pas grand chose,

sur les HQL :

  • pour les fin connaisseurs de SQL, l’apprentissage s’en trouve réduit,
  • comme c’est une chaîne, la (mauvaise) habitude de concaténer les arguments peut vite arriver, au lieu d’utiliser les paramètres (SetParameter), et ça, c’est mal,
  • la syntaxe étant une chaîne, cela peut être pratique de mettre en place un système d’indicateurs où il y aurait les requêtes à exécuter dans un fichier par exemple (ie: requêtes statiques),

Au niveau performances, il peut y avoir une légère différence, mais pour le Web, lorsqu’il s’agit d’afficher une page, ce n’est pas un critère discriminant.

Personnellement, je penche pour HQL, bien plus proche du SQL, et NH permet d’avoir un langage d’interrogation objet, autant l’exploiter.

Ressources

On pourra essayer cet intéressant projet, plugin NHibernate pour R#.

Nouvelles du monde : retour à la “civilisation numérique”

Posted by – September 5, 2008

C’est la rentrée, du moins pour votre hôte qui revient de quelques semaines de congés bien méritées, et on est bien ressourcé pour débuter la rentrée comme il se doit. Afin de redémarrer la machine doucement, quelques nouveautés et évènements à venir, ainsi qu’un résumé de mon périple en Afrique.

Nouveautés

NHibernate 2.0 est dans les bacs, la 2.1 prévoit dès lors une intégration de Linq To NHibernate (les sources).

Tout le monde en parle, Google Chrome, le nouveau challenger à IE / Firefox / Safari / Opéra, et peut-être également un nouveau défi pour les développeurs avec cet nième navigateur, même si le moteur de rendu est basé sur le même que Safari (Webkit html). Première impression : impressionnant d’efficacité pour sa rapidité d’affichage. On retrouve les fonctions de tout navigateur du XXI è siècle : onglets, conforme aux standards, simple. Quelques différences toutefois :

  • affichage lisible du site en cours (en noir), le reste (protocole, pages) reste en gris, cela permet de visualiser tout de suite l’adresse, cela contribue à la lutte contre le pishing,
  • ouverture d’une fenêtre de navigation privée : aucun historique ne sera conservé, ni cookies, pratique pour naviguer sur des sites de geeks…par exemple, à l’insu de sa femme,
  • la barre habituellement réservée à l’URL sert également de barre de recherche avec des suggestions,
  • import de l’historique, mots de passe enregistrés de Firefox ou IE,

En revanche, quid des extensions à la Firefox, espérons que cela viendra. Google Chrome est déjà très prometteur, et faisons confiance à Google pour monter en fonctionnalités ce navigateur. Retrouvez également les mêmes fonctionnalités que Chrome sous Firefox grâce à un ensemble d’extensions.

Les rendez-vous de la rentrée

L’agenda de quelques évènements courant septembre et octobre :

Ma vie, mon oeuvre

Blog : à part ces drôles de nouvelles passionnantes, à peine arrivé, que je m’aperçois que le serveur hébergé à la maison est HS (apparemment depuis 5 jours), un des disques a rendu l’âme (qui contient toutes les partitions LVM donc…), d’où une absence du blog non désirée. Merci à Google qui garde en cache les pages, gain de temps pour réinstaller le tout sur une nouvelle machine grâce à ce billet Debian + VServer, et aussi aux sauvegardes effectuées sur mon NAS. A faire : trouver un hébergement pas cher, un serveur virtualisé suffira, du moment qu’on peut le gérer.

Fracture numérique : de retour d’un séjour en Afrique, plus précisemment de Côte d’Ivoire, ex-fleuron de l’afrique de l’ouest. Là-bas, il y a bien Internet, et même l’ADSL. Le seul hic, le débit : ADSL à … 10 ko /s (j’arrive en France parfois à atteindre 650 ko/s en petite couronne de Paris), et ce, pour un prix modique de 50 à 100 € (33 000 à 65 000 CFA), sans TV, ni téléphone, uniquement Internet. Et dire qu’on parle déjà dans nos contrées de débits à 100 Mb par fibre optique, il y a un fossé effectivement entre les 2 mondes, la fracture numérique existe bien. Alors, 10 ko/s, ça m’a rappelé le bon vieux temps : télécharger Skype met environ 35 mn, mettre à jour Windows devient mission impossible, la moindre action nous plonge dans un apprentissage de la patience, associée à l’espoir que le téléchargement ne plantera pas. Je souhaitais aussi rajouter de la mémoire à un vieux PC, de la SDRAM, la barette de 512 Mo coûte…100 €, sic. On attendra donc de ramener là-bas un portable d’occasion à 100 $ que je peux avoir. Voilà pour l’expérience des nouvelles technologies dans un pays bien plus développé que d’autres (Burkina, Libéria, Sénégal, …), on imagine donc les moyens chez ces voisins. Heureusement, des initiatives, telle que 03b apparaisse pour tenter de combler ce fossé entre les pays dits industrialisés et les pays émergents. Google fait bien entendu parti de l’aventure, on ne peut que remercier ce type de projet. A faire : pour la prochaine fois, acheter du matériel en France pour la famille, et arrêter de me plaindre quand je n’ai que 250 ko/s en débit.

Pour finir sur une note d’humour : le blues des développeurs

…et allons lire les 3 000 liens en stock dans mes flux RSS laissés en stand-by depuis mi-août.

NHibernate : IoC (Castle Windsor), multi-bases, et relation one-to-one (composition)

Posted by – August 2, 2008

Introduction

Poursuivons notre découverte de quelques principes concernant les ORM ou la POO. Dans notre exemple de bibliothèque de médias, je souhaite maintenant appliquer les points suivants :

  • utilisation de plusieurs bases (MySQL, SQLite, MSSQL),
  • représenter une composition entre un média et sa pochette éventuelle (image),
  • utiliser un framework IoC, le conteneur Castle Windsor afin d’instancier les contrôleurs

More

Links #7 : migration et schéma de bases de données

Posted by – July 29, 2008