Archive

Articles taggués ‘NHibernate’

Architecture d’une application Windows en .NET

On m’a récemment demandé un avis sur l’architecture d’une application Windows écrite en .NET. Bien que l’exercice soit toujours difficile car cela dépend bien évidemment du contexte, je profite de ce billet pour donner quelques pistes de réflexions quand au choix des briques logicielles. Le demandeur venant du monde Java, mon discours sera orienté dans ce sens.

  • Outil de mapping objet relationnel : à mon sens, il y a aujourd’hui 2 alternatives en .NET :
    1. NHibernate, le cousin germain de Hibernate. Pour éviter la configuration dans les fichiers XML, je conseille le mode fluent ainsi que l’API de requêtage  LINQ . Un début de présentation est disponible ici. Sinon, il y a aussi les slides de la formation en soirée qui a été animée l’automne passé.
    2. Entity Framework. La dernière version reprend des principes de NHibernate, dont notamment la programmation par POCO (Plain Old C# Object), le lazy loading (chargement tardif). Comme je le mentionnais dans ce billet, plusieurs modes sont disponibles : Database first, Model First et maintenant Code First, très proche de Fluent NHibernate. Un atelier en soirée aura lieu fin mai sur ce thème.
  • Spring.NET : je trouve la question délicate, car cela dépend vraiment du besoin (IoC, programmation par aspects, boîte à outils,  framework MVC …). Comme son cousin Java, c’est une véritable boîte à outils très (trop ?) riche. Cette richesse est parfois synonyme de complexité et de lourdeur, par rapport à d’autres conteneurs IoC tels que NInject, Autofac, StructureMap, Castle Windsor ou Unity. Son principal inconvénient était sa configuration « XML based ». Ce point devrait être adressé avec la sortie de CodeConfig. Sa proximité avec son cousin est souvent un critère de choix pour des équipes mixtes (Java/NET).
  • NUnit : très proche de son cousin Java JUnit, il est également basé sur des attributes. Dans le monde ouvert, j’apprécie également MBUnit maintenant inclus dans le framework Gallio. Pour intégrer ces frameworks open-source dans un IDE tel que Visual Studio, je conseille test driven.net. Microsoft fournit également son propre framework,  qui ressemble beaucoup à NUnit et qui est très bien intégré dans Visual Studio. J’avoue l’utiliser très souvent. J’aime particulièrement la structuration par projet, qui fonctionne également pour tester des classes « internal ». J’aime également la facilité avec laquelle on peut écrire des tests orientés données, en prenant un fichier CSV pour indiquer les paramètres d’entrée et les paramètres de sortie.
  • Un équivalent à Mockito. Ne l’ayant pas utilisé sur un projet, la réponse risque d’être déplacée. Néanmoins, j’utilise parfois moq ou NMock. Je suis preneur d’un comparatif 😉
  • Pour la base de données, encore une fois je penche pour la facilité d’intégration et donc pour une solution SQL Server Express, ou SQL Server Compact, selon l’usage. Les deux solutions sont gratuites.

Je termine par un outil que je trouve très utile, qui est maintenant intégré à Visual Studio 2010 SP1 et qui permet de gérer des librairies externes, un maven like light : NuGet.

Presentation d’Entity Framework

Voici un premier billet présentant de manière générale l’outil de mapping objet relationnel proposé par Microsoft : Entity Framework. Je proposerai par la suite d’autres billets sur des points spécifiques au mapping objet relationnel tels que :

  • les identifiants
  • les associations entre entités
  • l’héritage
  • les stratégies de chargement

Afin de lever toute ambiguïté, je tiens à préciser que j’arrive du monde Hibernate, un outil de mapping objet relationnel open source reconnu et aujourd’hui normalisé avec JPA (Java Persistence API). C’est pourquoi je ferai régulièrement référence à cet outil que j’apprécie particulièrement. Ceux qui connaissent (N)Hibernate ne seront pas trop dépaysés car certains mécanismes ont été repris.

La première version d’Entity Framework ne m’a pas vraiment convaincu.

  • L’idée fondamentale qui est de séparer le modèle conceptuel (CSDL : Conceptual Schema Definition Language), du modèle logique de bases de données (SSDL : Store Schema Definition Language) en détaillant le mapping dans un schéma de liaison (MSL : Mapping Specification Language) est théoriquement très intéressant mais se révèle assez lourd dans la pratique : le designer proposé dans Visual Studio étant limité, il faut très rapidement éditer LE fichier XML manuellement qui est encore plus verbeux qu’un fichier de mapping Hibernate !
  • Par ailleurs, les objets entités étaient nécessairement très liés au framework : héritage d’implémentation, utilisation de collections propres à EF…
  • L’approche outillée était une approche relationnelle : à partir d’un modèle relationnel et EF génère des classes persistantes.

Avec la nouvelle version (Entity Framework 4), et notamment avec Entity Framework Feature CTP 3, également connu sous le nom de code-first, je commence à trouver l’outil très intéressant.

Comme son nom l’indique, code-first permet d’écrire des classes en premier, puis de générer un modèle relationnel issu de ces classes. C’est cette approche que je vous propose d’aborder dans ces billets avec la modélisation d’un système d’information (très simplifié) d’une banque. Dans une banque le client est roi, nous commencerons donc par la classe Client:

public class Client{
   public int Id { get; set;}
   public string Nom { get; set;}
   public string Prenom { get; set;}
}

Pour fournir à Entity Framework les informations de mapping, nous utiliserons le mode fluent. Pour cela, on définit généralement une classe de configuration par entité qui étend de EntityConfiguration<T>.

public class ClientConfiguration : EntityConfiguration<Client>{
   public ClientConfiguration(){

   // la propriété Id est l'identifiant de base de données
   this.Property( client => client.Id)
        .IsIdentity();

   // la propriété Nom ne peut pas être null
   // elle a une taille max de 200
   this.Property( client => client.Nom)
        .IsRequired()
        .HasMaxLength(200);
   }
}

Cette manière d’utiliser les lambdas expressions est de plus en plus fréquente en C#. On la retrouve notamment dans Fluent Nhibernate. Les fichiers de mapping XML sont contraignants à éditer et à maintenir. Les annotations sont plus simples d’utilisation mais leur présence dans nos classes POCO impliquent une forme d’adhérence vers le framework : une dépendance de compilation. Dans une application RIA avec Silverlight , il est fréquent de référencer l’assembly contenant le modèle du domaine. Mais une dépendance de compilation des classes du domaine vers un framework de mapping objet relationnel rend caduque ce référencement. Le mode fluent permet de décrire le mapping dans une assembly tierce, sans la lourdeur du XML avec en prime une vérification au moment de la compilation, de la complétion et du refactoring !

Je détaillerai dans mon prochain billet la configuration du ContextBuilder à partir de nos classes de configuration. C’est l’équivalent de la SessionFactory. Une fois configurée, cette fabrique va permettre  à EF de générer notre schéma de bases de données. Par défaut, il va créer une table Clients avec 3 colonnes :

  1. Id : la clé primaire de la table auto incrémentée
  2. Nom : un nvarchar de 200 non null
  3. Prenom

Nous avons vu dans ce premier billet la mise en place d’un mapping simple entre un POCO vers une base de données relationnelle, les éléments de mapping étant fournis dans une classe C# en mode fluent.

Categories: .NET Tags: , ,

Charger une association dans WCF RIA Services

Je l’avais annoncé ici : .NET RIA services est devenu WCF RIA Services.

Rappels

L’objectif de ce projet est de simplifier le développement d’applications RIA.

Le principe général est assez simple :
Je développe des services de domaine (CRUD + Queries) en utilisant des conventions de nommage côté serveur.

Par exemple, la méthode Sprint LoadSprint(int sprintId) renvoie un sprint d’une application Scrum à partir de son identifiant.

WCF RIA Services projette ce code côté client dans des classes de type DomainContext.

Dans notre exemple, j’obtiens une classe ScrumDomainContext avec une méthode EntityQuery<Sprint> LoadSprintQuery(int sprintId)

Projection de code

Projection de code

Les associations

La version beta est disponible depuis le mois de Novembre. On trouve sur le Web quelques introductions, notamment celles de Brad Abrams. En revanche, on trouve très peu de choses sur comment charger une association dans notre application cliente Silverlight.

Dans mon exemple, je veux afficher une vue Master/Details qui présente un sprint et la liste de ses tâches.

Le modèle

Sprint association

Sprint association

La déclaration de l’association

Je dois ensuite décrire à WCF Ria services les associations entre mes entités. Pour cela, je décore les propriétés Tasks de la classe Sprint, et Sprint de la classe Task avec l’annotation AssociationAttribute. Il faut indiquer un nom pour cette association, par exemple Sprint_Tasks et préciser les clés étrangères de chacune de ses relations. Dans le sens Sprint -> Task, la clé c’est le champ Id de la classe Sprint et la clé étrangère c’est le champ SprintId de la classe Task.


public class Sprint{
[Key]
public virtual int Id { get; set; }

[Association(« Sprint_Task », « Id », « SprintId »)]
public virtual ICollection Tasks { get; set; }
}

Quelques remarques :

  1. Les habitués de NHibernate vont déplorer le fait d’avoir à décrire l’association à l’aide des clés étrangères. Cela nécessite par ailleurs d’avoir une propriété SprintId dans la classe Task en plus de la propriété Sprint :(
  2. La décoration est automatique avec l’utilisation de LinqToSql ou d’Entities Framework

Le chargement explicite

Il reste enfin à indiquer explicitement que l’on souhaite sérialiser les tâches avec le sprint. Pour cela, nous devons définir une classe de méta données relative à la classe métier. Dans notre exemple, ce sera une classe SprintMetaData définissant un champ Tasks que l’on décore avec l’annotation IncludeAttribute.


public class SprintMetaData {
[Include]
public EntitySet Tasks;
}

Je vous laisse regarder le blog de Brad Adams ou un ancien billet pour les détails de la classe de méta données.

Personnellement je trouve dommage d’avoir à définir une stratégie de chargement dans un fichier de méta données. L’idée générale n’est pas mauvaise, mais présente un inconvénient majeur : la stratégie est valable pour tous les cas d’utilisation. Or il est probable que l’application ne nécessite à la fois le sprint et ses tâches que dans certains écrans …

Outils de mapping objet/relationnel

Si vous utilisez un ORM, n’oubliez pas de récupérer la collection de tâches dans votre requête.

Avec LinqToEntities, ça donne :


public Sprint LoadSprint(int sprintId){
return this.Context.Sprints
.Include("Tasks")
.Where(sprint=>sprint.Id == sprintId);
}

Avec LinqToNhibernate, ça donne:


public Sprint LoadSprint(int sprintId)
{
var result = this.Session.Linq().Expand("Tasks")
.Where(x => x.Id == sprintId)
.ToList().First();
return result;
}

Conclusion

Nous avons vu en détail comment charger une association entre deux entités dans une application WCF Ria Services. Une partie de ces détails est masquée par l’outillage fourni par Microsoft et nous ferait presque oublier la complexité qui ne manquera pas de ressortir si vous souhaitez utiliser cette pile en association avec des outils tel que NHibernate

Linq to NHibernate

Sur le champ de bataille des ORM en .NET, NHibernate a fait une percée importante pendant ces vacances estivales avec le support de Linq. L’annonce d’Ayende est ici.

Regardons quelques exemples classiques d’utilisation. Nous partirons du modèle suivant, issu d’un guide sur Fluent NHibernate.

Notre modèle

Filtrer une liste d’entités sur une propriété:

var query = from store in session.Linq<Store>()
where store.Name == « SuperMart »
select store;

Charger une collection mappée avec un chargement tardif (lazy loading):

var query = from store in session.Linq<Store>()
from product in store.Products
where store.Name == « SuperMart »
select store;

Attention toutefois, car cette requête retourne un produit cartésien (n objets store identiques avec une collection chargée, n étant le nombre de produits associés au store) et non un arbre d’objets.

Écrire une requête dynamique filtrée sur une collection:

// la requête initiale

var query = from store in session.Linq<Store>()
from staff in store.Staff
from product in store.Products
select store;

// on rajoute dynamiquement des critères de recherche en rajoutant des contraintes à l’arbre d’expressions

var employee = « Harrison »;
query = query.Where(x => x.Staff.Any(y => y.LastName == employee));

Avantages de cette alternative

  • Les requêtes sont vérifiées à la compilation
  • L’IDE vous propose la complétion et le refactoring
  • Vous pouvez toujours utiliser l’API classique (ce n’est qu’un facilitateur)
  • La syntaxe est proche d’une syntaxe SQL
  • Cerise sur le gâteau : la publication de données avec ADO.NET Data Services va être possible avec NHibernate

Remarque:

  • L’implémentation n’est pas encore complète et peut conduire à des effets de bord inattendus (cf la remarque sur le produit cartésien)
Categories: .NET Tags: , , ,