Traduction▲
Cet article est la traduction la plus fidèle possible de l'article original de Brad Abrams, Business Apps Example for Silverlight 3 RTM and .NET RIA Services July Update: Part 20: NHibernate.
Article▲
Je m'éclate avec cette série où je mets à jour ma simple démo d'application métier du Mix09. Dans cette partie, je voulais explorer l'une des solutions d'accès aux données pour .NET les plus populaires : NHibernate. De nombreux clients trouvent que la flexibilité de NHibernate facilite le développement d'applications maintenables et testables. Soit dit en passant, je pense que NHibernate est un excellent exemple du dynamisme de la communauté open source .NET, que je voudrais soutenir.
Vous pouvez trouver la série complète ici.
Cette démo nécessite les éléments suivants (tout est 100 % gratuit) :
- Visual Studio 2008 SP1 (qui inclut SQL Server Express 2008) ;
- Silverlight 3 RTM ;
- .NET RIA Services July '09 Preview ;
- NHibernate (avec NHibernate Linq) et Fluent Nhibernate.
Téléchargez aussi les fichiers de la démo complète, et jetez un œil à l'application en cours d'exécution.
En fait, tout ce que je voulais faire, c'était modifier mon DomainService pour qu'il ne récupère plus ses données d'Entity Framework mais de NHibernate. Le reste de l'application reste effectivement inchangé.
Pour commencer, j'ai récupéré le code du tutoriel précédent, et j'ai supprimé le fichier edmx.
Voilà ci-dessous le code que j'utilise pour créer la SessionFactory NHibernate. L'interface fluide rend cela très facile à configurer.
1
:
static
ISessionFactory SessionFactory =
CreateSessionFactory
(
);
2
:
static
ISessionFactory CreateSessionFactory
(
)
3
:
{
4
:
return
Fluently.
Configure
(
)
5
:
.
Database
(
6
:
MsSqlConfiguration.
MsSql2005
7
:
.
ConnectionString
(
c =>
c
8
:
.
Is
(
ConfigurationManager.
ConnectionStrings[
"MainConnStr"
].
ConnectionString)
9
:
)
10
:
)
11
:
.
Mappings
(
m =>
12
:
m.
FluentMappings.
AddFromAssemblyOf<
SuperEmployeeDomainService>(
))
13
:
.
BuildSessionFactory
(
);
14
:
15
:
}
Ensuite, regardons la classe de mapping. Elle indique comment les données de la base sont mappées sur une classe .NET.
1
:
public
class
SuperEmployeesMap :
ClassMap<
SuperEmployee>
2
:
{
3
:
public
SuperEmployeesMap
(
)
4
:
{
5
:
WithTable
(
"SuperEmployees"
);
6
:
Id
(
x =>
x.
EmployeeID);
7
:
Map
(
x =>
x.
Name);
8
:
Map
(
x =>
x.
Gender);
9
:
Map
(
x =>
x.
Issues);
10
:
Map
(
x =>
x.
LastEdit);
11
:
Map
(
x =>
x.
Origin);
12
:
Map
(
x =>
x.
Publishers);
13
:
Map
(
x =>
x.
Sites);
14
:
}
15
:
}
Et voilà le type sur lequel je mappe les données. Remarquez les attributs de validation pour RIA Services pour effectuer la validation sur le client et sur le serveur.
1
:
public
class
SuperEmployee
2
:
{
3
:
[
Key]
4
:
[
ReadOnly
(
true
)]
5
:
public
virtual
int
EmployeeID {
get
;
set
;}
6
:
7
:
[
RegularExpression
(
"^(?:m|M|male|Male|f|F|female|Female)$"
,
8
:
ErrorMessage =
"Gender must be 'Male' or 'Female'"
)]
9
:
public
virtual
string
Gender {
get
;
set
;
}
10
:
11
:
[
Range
(
0
,
10000
,
12
:
ErrorMessage =
"Issues must be between 0 and 1000"
)]
13
:
public
virtual
Nullable<
int
>
Issues {
get
;
set
;
}
14
:
15
:
public
virtual
Nullable<
DateTime>
LastEdit {
get
;
set
;
}
16
:
17
:
[
Required]
18
:
[
StringLength
(
100
)]
19
:
public
virtual
string
Name {
get
;
set
;
}
20
:
21
:
public
virtual
string
Origin {
get
;
set
;
}
22
:
23
:
public
virtual
string
Publishers {
get
;
set
;
}
24
:
25
:
public
virtual
string
Sites {
get
;
set
;
}
26
:
}
C'est l'essentiel du code spécifique à NHibernate. Revenons maintenant au DomainService.
1
:
[
EnableClientAccess
(
)]
2
:
public
class
SuperEmployeeDomainService :
NHibernateDomainService
3
:
{
4
:
public
SuperEmployeeDomainService
(
) :
5
:
base
(
SessionFactory) {
}
D'abord, à la ligne 2, remarquez que j'ai factorisé une partie du code de « plomberie » dans une classe de base. C'est un exemple très simple (pas prêt pour la production). On y reviendra plus en détail après. Ensuite, on envoie la SessionFactory à la classe de base. La SessionFactory est statique afin qu'elle soit créée une seule fois par AppDomain, plutôt qu'à chaque requête.
1
:
public
IQueryable<
SuperEmployee>
GetSuperEmployees
(
)
2
:
{
3
:
return
Session.
Linq<
SuperEmployee>(
)
4
:
.
Where
(
e =>
e.
Issues >
10
);
5
:
}
Ici on utilise NHibernate Linq pour renvoyer un IQueryable que RIA Services peut utiliser pour faire la pagination, le filtrage, etc.
On a ensuite l'insertion et la mise à jour qui sont très basiques.
1
:
public
void
InsertSuperEmployee
(
SuperEmployee superEmployee)
2
:
{
3
:
Session.
Save
(
superEmployee);
4
:
}
5
:
6
:
public
void
UpdateSuperEmployee
(
SuperEmployee currentSuperEmployee)
7
:
{
8
:
Session.
Update
(
currentSuperEmployee);
9
:
}
Maintenant, regardons la classe de base NHibernateDomainService. Encore une fois, c'est assez basique, juste pour montrer les concepts.
1
:
public
class
NHibernateDomainService :
DomainService
2
:
{
3
:
4
:
protected
ISession Session;
5
:
6
:
public
NHibernateDomainService
(
ISessionFactory sessionFactory)
7
:
{
8
:
this
.
Session =
sessionFactory.
OpenSession
(
);
9
:
}
10
:
11
:
12
:
protected
override
void
Dispose
(
bool
disposing)
13
:
{
14
:
Session.
Dispose
(
);
15
:
base
.
Dispose
(
disposing);
16
:
17
:
}
18
:
protected
override
void
ExecuteChangeSet
(
ChangeSet changeSet)
19
:
{
20
:
using
(
var
trans =
Session.
BeginTransaction
(
))
21
:
{
22
:
base
.
ExecuteChangeSet
(
changeSet);
23
:
trans.
Commit
(
);
24
:
}
25
:
}
Remarquez qu'on crée la session dans le constructeur. Ensuite on la ferme dans la méthode Dispose().
La partie intéressante est la gestion du ChangeSet. Remarquez qu'on utilise une transaction pour encadrer les appels à nos méthodes de mise à jour et de création. Cela permet de s'assurer que s'il y a une erreur, on annule les changements (c'est le contrat pour DomaineService).
Maintenant, puisqu'on s'intègre dans le modèle du DomainService, on a notre client Silverlight avec la pagination, le filtrage, etc.
Et la validation de la saisie
Mais on a aussi le support d'ASP.NET via la DomainDataSource, comme dans cet exemple tiré du fichier sitemap.aspx.
1: <asp:DomainDataSource runat
=
"server"
ID
=
"SitemapDataSource"
2: DomainServiceTypeName
=
"MyApp.Web.SuperEmployeeDomainService"
3: SelectMethod
=
"GetSuperEmployees"
/>
Et on a une interface basée sur REST via le support d'Astoria pour DomainService.
Et on a le support d'ASP.NET Dynamic Data, toujours avec la pagination, le filtrage, etc.
Et la validation de la saisie.
Et toutes les autres couches de présentation.
Pas mal, non ?
Pour plus d'informations sur NHibernate, faites un tour sur le blog d'Ayende.
Pour plus d'informations sur NHibernate et DomainService, allez voir le billet blog de Chris van de Steeg ASP.NET MVC, DynamicData, Domain-/RiaServices, Unity and NHibernate: Part 1.
Conclusion▲
Ceci conclut la vingtième partie de cette série. La partie suivante traitera des données hiérarchiques.
Remerciements▲
Je tiens ici à remercier Brad Abrams de nous avoir autorisés à traduire son article.
Je remercie également ClaudeLELOUP pour sa relecture et ses propositions.