Jiri's Shared IT knowledge

mercredi, août 02, 2006

Microsoft dévoile C# v3 et le projet Linq (Suite)

Linq

Le principe de Linq consiste à proposer un ensemble d'opérateurs pouvant être redéfinis et enrichis par toute implémentation tierce. Microsoft fournit deux implémentations : Dlinq pour la partie mapping objet/relationnel et Xlink pour la partie XML. Cette architecture est illustré par le schéma suivant :

















Une requête simple
Le langage propose dorénavant la possibilité de requêter directement une collection (implémentant IEnumerable) en utilisant des mots clés réservés, démonstration :

using System;
using System.Query;
using System.Collections.Generic;
class app {
static void Main() {
string[] auteurs = { "Roger", "Bilou", "Thomas",
"Titi", "Lou", "Eric",
"Toto"};
IEnumerable<string> expr = from s in auteurs
where s.Length == 5
orderby s
select s.ToUpper();
foreach (string item in expr)
Console.WriteLine(item);
}
}

L'exécution de cette fonction affichera : ROGER, BILOU .

Sous le capot, les mots clés Where, OrderBy et Select sont pré-processés par le compilateur pour générer une expression plus proche de la sémantique habituelle des langages objets. Le code suivant est le résultat de la compilation.

IEnumerable<string> expr = names
.Where(s => s.Length == 5)
.OrderBy(s => s)
.Select(s => s.ToUpper());

Ceux qui ont l'habitude des outils de mapping objet/relationnel reconnaîtront une syntaxe proche de l'arbre d'expressions utilisé par des outils tels que Hibernate. En revanche l'innovation est criante lorsqu'il s'agit du typage de l'expression. Là où la plupart des outils de mapping se reposent sur un requêtage plutôt textuel et donc faiblement typé, C# propose l'exécution d'une expression lambda. Il suffit d'appréhender le paramètres s=>s.Length == 5 comme le code d'un simple délégué .NET qui sera passé au moteur de mapping.

Lors de la phase de requêtage, C# créé un arbre d'expression (un arbre de délégués) constitué de toute une panoplie d'opérateurs spécialisés, de prédicats aux projections en passant par les filtres et les tris, puis réalise l'interprétation de cet arbre lors de l'invocation finale ... Toute la force du lambda calcul au service de C# et du mapping objet. Une approche totalement déroutante qui va certainement susciter de grands débats dans les jours prochains.

Mapping Objet/XML
Xlink est la partie mapping XML. Ce Framework propose toute une hiérarchie de classes (un équivalent de DOM). La création d'un document consiste à tirer partie de ces classes de la manière suivante :

string myNs = "{http://dng.com}";
XElement auteurs= new XElement(myNs+"auteurs",
new XElement(myNs+"auteur",
new XElement(myNs+"nom", "Thomas Gil"),
new XElement(myNs+"telephone", "098766",
new XAttribute("ou", "maison")),
new XElement(myNs+"telephone", "098765",
new XAttribute("ou", "bureau")),
new XElement(myNs+"adresse",
new XElement(myNs+"rue", "5, rue titi"),
new XElement(myNs+"ville", "Paris"),
)
)
);

Ce code génèrera le document suivant :

http://dng.com">

Thomas gil
maison">098766
bureau">098765

5, rue titi
Mercer Island




Rechercher une information avec l'API Query consistera à faire :

XElement auteurs = new XElement("auteurs",
from p in auteurs
select new XElement("auteur",
new XElement("nom", p.Nom),
from ph in p.Telephone
select new XElement("telephone", ph)
)
);
Console.WriteLine(auteurs);

Mapping Objet/Relationnel
Le meilleur pour la fin. Que ceux qui pensaient que Microsoft avait abandonné à tout jamais le mapping objet/relationnel se rassurent. Non seulement il revient en force mais il sera au coeur de la plupart des futures applications WinFX de l'éditeur. S'il est vrai aujourd'hui qu'il reste encore des pans de fonctionnalités à combler, l'essentiel est là, il s'appelle dlinq. Assez de littérature, voyons maintenant du code. Voici un exemple de création et modification d'enregistrement dans une base relationnelle sur le même modèle que l'exemple XML précédent :

Northwind db = new Northwind("c:\\northwind\\northwnd.mdf");
// Recherche un auteur particulier
string id = "1";
var auteur = db.Auteurs.First(c => c.AuteurID == id);
// Change le nom de l'auteur
auteur.Nom = "L'ami S'ami";
// Recherche un article de cet auteur
Article article= auteur.Articles[0];
// L'enlève de la table et de la liste des articles
db.Articles.Remove(article);
// Créé un nouvel article et l'ajoute à la collection
Article art = new Article{ articleId = 12345 };
auteur.Articles.Add(art);
// Demande au persistence manager de sauver l'objet
db.SubmitChanges();

Vous souhaitez faire une requête ? Rien de plus simple :

var result =
from c in db.Auteurs
where c.Ville == "Paris"
select c;
foreach (Auteur auteur in result)
Console.WriteLine(auteur.Nom);

Et le modèle du domaine ? Le voilà :

[Table(Name="Articles")]
public class Article
{
[Column(Id=true)]
public int ArticleID;

[Column]
public string ArticleID;

private EntityRef<Auteur> _Auteur;

[Association(Storage="_Auteur", ThisKey="AuteurID")]
public Auteur Auteur{
get { return this._Auteur.Entity; }
set { this._Auteur.Entity = value; }
}
}

Une forme d'écriture très proche de ce qu'on retrouve sur le marché dans le domaine. Aujourd'hui, le Framework propose plusieurs opérateurs, de nombreuses fonctionnalités sont couvertes telles que :

- le Lazy Loading (appelé Deffered Loading)
- la gestion des relations (0,n - 1,1, etc..)
- la gestion du cycle de vie d'une entité
- les procédures stockées
- Un générateur de modèle du domaine à partir d'un fichier de configuration (appelé SQLMetal)
- Un générateur de fichier de configuration à partir d'un modèle du domaine
- L'attachement et le détachement

En revanche, il reste encore à couvrir :

- L'héritage et les requêtes polymorphiques

Quant aux transactions, voici un exemple qui devrait rassurer :

using(TransactionScope ts = new TransactionScope())
{
db.UseLocalTransactionsOnly = true;
db.SubmitChanges();
ts.Complete();
}

Tout naturellement l'API System.Transactions aura la charge de gérer les propriétés transactionnelles des entités. Enfin !

Conclusion
C# V3 et le Framework Linq sont une révolution pour Microsoft même si aujourd'hui il est encore difficile d'entrevoir l'impact de tels changements. Jamais l'éditeur n'avait pris un tel risque technologique tant d'un point de vue de l'implémentation que du de design. Depuis la création de DNG, nous n'avons cesse d'insister sur l'importance des concepts de séparation des couches, de persistance, d'architecture orientées services. Tout ce dont on rêvait pour .NET prend aujourd'hui forme avec même une tournure plutôt radicale qui a tendance à dérouter. Utiliser des expressions lambda comme base d'un langage de requête, il fallait oser. Dorénavant à la question "where do you want to go today ?" difficile de répondre autrement que par "to the fucking shiping date ". Car à force d'attendre , on risque de perdre patience...

Source :http://www.dotnetguru.org/