NHibernate - Guide rapide
Dans ce chapitre, nous discuterons de ce qu'est NHibernate, de toutes les plates-formes sur lesquelles il peut être implémenté, de ses avantages et d'autres aspects qui y sont liés.
Qu'est-ce que NHibernate?
NHibernate est un mappeur objet-relationnel mature et open source pour le framework .NET. Il est activement développé, complet et utilisé dans des milliers de projets réussis. Il est construit au-dessus deADO.NET et la version actuelle est NHibernate 4.0.4.
NHibernate est un mappeur relationnel objet .NET open-source et est distribué sous le GNU Lesser General Public License.
Il est basé sur Hibernate qui est un mappeur relationnel objet Java populaire et il a une base de code très mature et active.
Il fournit un cadre pour mapper un modèle de domaine orienté objet vers une base de données relationnelle traditionnelle.
NHibernate a été lancé par Tom Barrett et ce projet existe depuis février 2003, qui était leur premier engagement.
C'est un gros projet et offre beaucoup de fonctionnalités.
Il y a un NuGet package disponible, ce qui rend très facile l'ajout à un projet.
Pourquoi NHibernate?
Maintenant, la question est de savoir pourquoi avons-nous besoin object-relational mappers? C'est parce qu'il y a une déconnexion entre le monde des objets et le monde relationnel.
Dans le monde des objets, tout est basé sur objects; nous appelons objets ces choses qui contiennent nos données.
Le monde relationnel est entièrement basé sur des ensembles et nous avons affaire à des tables et des lignes qui sont différentes du monde objet.
Dans le monde des objets, nous avons unidirectional associations. Si un client a un pointeur vers une commande, cela ne signifie pas nécessairement qu'une commande a un pointeur vers un client, cela peut ou non.
Dans le monde relationnel, toutes les associations sont bidirectional et cela peut être fait par une clé étrangère.
Toutes les associations sont intrinsèquement bidirectionnelles, donc lorsque nous traitons de mappage objet-relationnel, nous devons également gérer cette déconnexion.
Dans le monde des objets, nous travaillons avec des pointeurs unidirectionnels, alors que dans le monde relationnel, nous avons des clés étrangères qui sont intrinsèquement bidirectionnelles.
Le monde des objets a cette notion d'héritage, où un véhicule peut avoir un certain nombre de sous-classes différentes, donc une voiture est un type de véhicule, un bateau est un type de véhicule et une voiture de sport est un type de voiture, ces types de relations d'héritage.
Le monde relationnel n'a pas cette notion d'héritage.
Cartographie
Alors, comment cartographier tous ces disjoint relationships?Ce concept de mappage vient du mappeur objet-relationnel. Il y a principalement trois choses à comprendre comme indiqué dans le diagramme suivant.
Dans votre application, vous aurez besoin de définitions de classe, qui sont généralement du code C # et son code .NET qui représente nos classes, telles que la classe Employee, la classe Customer, la classe Order, etc.
En bas, vous pouvez voir un schéma de base de données, qui est notre Data Definition Language dans une base de données relationnelle qui spécifie à quoi ressemble une table client, à quoi ressemble une table d'employé.
Entre ceux-ci, nous avons les métadonnées de mappage qui indiquent au mappeur relationnel objet comment traduire du monde objet en C # au monde de la base de données en termes de lignes et de colonnes et de relations de clé étrangère.
Ces métadonnées de mappage peuvent être représentées de différentes manières et nous examinerons un certain nombre de ces différentes manières les plus courantes dans l'application NHibernate.
Il est représenté par HBM (Hibernate Mapping) fichiers, qui sont des fichiers XML.
Base de données prise en charge
NHibernate prend en charge une grande variété de bases de données différentes. Toute base de données relationnelle existante est accessible à NHibernate.
Le serveur SQL est la base de données principale prise en charge, c'est ce que la plupart des développeurs utilisent pendant le développement, c'est probablement la plus courante.
Ça aussi works very well with Oracle.
Il prend également en charge DB2, Firebird, MySQL, PostgreSQL, SQL Lite
Cela a aussi ODBC and OLEDB drivers.
De nos jours, de nombreux systèmes sont conçus avec une architecture en couches, NHibernate l'a également et fonctionne parfaitement bien avec cette conception.
Architecture en couches
Une architecture en couches divise un système en un certain nombre de groupes, où chaque groupe contient du code adressant un problème particulier et ces groupes sont appelés couches. La plupart des applications de niveau entreprise utilisenthigh-level application architecture qui se composent de trois couches -
- La couche Présentation
- La couche métier
- La couche de persistance
Par exemple, une couche d'interface utilisateur également connue sous le nom de couche de présentation peut contenir tout le code d'application pour la création de pages Web et le traitement des entrées utilisateur.
L'un des principaux avantages de l'approche par couches est que vous pouvez souvent apporter des modifications à une couche sans interruption significative des autres couches, rendant ainsi les systèmes lesser fragile and more maintainable.
Couche de présentation
Il s'agit de la couche supérieure, qui contient le code responsable du dessin de l'interface utilisateur, des pages, des boîtes de dialogue ou des écrans, de la collecte des entrées utilisateur et du contrôle de la navigation.
Couche métier
La couche métier est responsable de la mise en œuvre des règles métier ou des exigences système que les utilisateurs comprendraient comme faisant partie du domaine du problème.
Il réutilise également le modèle défini par la couche de persistance.
Couche de persistance
La couche de persistance se compose de classes et de composants qui sont responsables de l'enregistrement et de la récupération des données d'application.
Cette couche définit également un mappage entre la classe de modèle et la base de données. NHibernate est principalement utilisé dans cette couche.
Base de données
- La base de données existe en dehors de l'application .NET.
- C'est la représentation réelle et persistante de l'état du système.
- Si une base de données SQL est utilisée, la base de données comprend le schéma relationnel et éventuellement des procédures stockées.
Classes d'assistance / utilitaire
Chaque application dispose d'un ensemble de classes d'assistance ou d'utilitaires qui prennent en charge les autres couches: par exemple, des widgets d'interface utilisateur, des classes de messagerie, des classes d'exception et des utilitaires de journalisation.
Ces éléments ne sont pas considérés comme des couches, car ils n'obéissent pas aux règles de dépendance intercouche dans une architecture en couches.
Architecture NHibernate
Il s'agit d'une vue de haut niveau de l'application NHibernate et vous pouvez également voir l'architecture simple de NHibernate.
Le code de l'application utilise le NHibernate ISession et IQuery API pour les opérations de persistance et ne doit gérer que les transactions de base de données, idéalement en utilisant NHibernate ITransaction API.
Avant de pouvoir vraiment commencer à utiliser NHibernate, nous devons comprendre les fondations sur lesquelles il est construit. NHibernate est une technologie de persistance basée sur l'idée de cartographie relationnelle objet ou ORM.
Qu'est-ce que l'ORM?
Object-Relational Mapping (ORM) est un programming techniquepour convertir des données entre des systèmes de types incompatibles dans des langages de programmation orientés objet. En d'autres termes, il s'agit du concept de mappage des objets métier d'une application sur des tables de base de données relationnelle, de sorte que les données puissent être facilement accessibles et entièrement mises à jour via le modèle objet d'une application.
Comme vous le savez déjà, les bases de données relationnelles constituent un bon moyen de stocker des données, tandis que la programmation orientée objet est une bonne approche pour créer des applications complexes.
NHibernate et ORM en général sont les plus pertinents pour les applications avec une logique métier non triviale, le modèle de domaine et une sorte de base de données.
Avec ORM, il est très facile de créer une couche de traduction qui peut facilement transformer des objets en données relationnelles et inversement.
L'acronyme ORM peut également signifier la modélisation de rôle d'objet, et ce terme a été inventé avant que le mappage objet / relationnel ne devienne pertinent.
Il décrit une méthode d'analyse des informations, utilisée dans la modélisation de bases de données.
Pourquoi ORM?
ORM est un framework qui vous permet de mapper le monde des objets trouvés dans les langages orientés objet aux lignes des tables relationnelles trouvées dans les bases de données relationnelles
Pour comprendre ce concept, jetons un œil au diagramme suivant.
Dans le diagramme ci-dessus, vous pouvez voir que nous avons une table appelée Employé sur le côté droit qui contient des colonnes avec chaque élément de données associé à un employé individuel.
Nous avons une colonne pour un identifiant qui identifie de manière unique chaque employé.
Une colonne pour le nom de l'employé, une autre colonne pour sa date d'adhésion et enfin une colonne qui a un âge d'un employé.
Si nous voulions écrire du code pour stocker un nouvel employé dans les tables, ce n'est pas si simple.
Dans le diagramme ci-dessus, vous pouvez également voir que nous avons un objet employé qui contient des champs pour l'ID, le nom, la date d'adhésion et l'âge.
Sans ORM, nous devons traduire cet objet en quelques instructions SQL différentes qui inséreront les données des employés dans la table des employés.
Donc, écrire du code pour créer le SQL pour faire le scénario ci-dessus n'est pas si difficile, mais c'est un peu fastidieux et assez facile de se tromper.
En utilisant un ORM comme NHibernate, nous pouvons déclarer comment certaines classes doivent être mappées sur des tables relationnelles et laisser l'ORM ou NHibernate s'occuper du travail désagréable de créer le SQL pour insérer, mettre à jour, supprimer, dans les données de requête dans notre table d'employés.
Cela nous permet de garder notre code concentré sur l'utilisation d'objets et de les traduire automatiquement en tables relationnelles.
Donc, ce que fait un ORM, c'est qu'il nous évite d'avoir à mapper manuellement des objets sur des tables.
Pour commencer à travailler sur NHibernate, nous aurons besoin de Visual Studio et du package NHibernate.
Installation de Visual Studio
Microsoft fournit un free version de Visual Studio, qui contient également SQL Server et il peut être téléchargé depuis https://www.visualstudio.com Voici les étapes de l'installation.
Step 1 - Une fois le téléchargement terminé, exécutez le programme d'installation, puis la boîte de dialogue suivante s'affiche.
Step 2 - Cliquez sur le bouton Installer et le processus d'installation démarrera.
Step 3 - Une fois le processus d'installation terminé avec succès, vous verrez la boîte de dialogue suivante.
Step 4 - Fermez cette boîte de dialogue et redémarrez votre ordinateur si nécessaire.
Step 5- Ouvrez maintenant Visual studio à partir du menu Démarrer qui ouvrira la boîte de dialogue suivante. Il faudra un certain temps pour la première fois pour la préparation.
Step 6 - Une fois tout cela fait, vous verrez la fenêtre principale de Visual Studio.
Installation du package NHibernate
NHibernate est un mappeur objet-relationnel mature et open source pour le framework .NET. Il est activement développé, complet et utilisé dans des milliers de projets réussis. Vous pouvez installer le package NHibernate avec les méthodes suivantes.
Téléchargement direct
Téléchargez le zip à partir du fichier depuis https://sourceforge.net/ qui contient tous les binaires nécessaires.
Extrayez ce fichier zip et incluez tous ces binaires dans votre projet.
Installer à l'aide de NuGet
Une autre façon d'installer NHibernate est d'utiliser NuGet pour installer le package NHibernate, qui est de loin le moyen le plus simple d'incorporer NHibernate dans un projet.
Il va télécharger toutes les dépendances NHibernate et créer des références à tous les assemblys requis.
Pour installer NHibernate, exécutez la commande suivante dans la console du gestionnaire de package.
install-package NHibernate
Vous êtes maintenant prêt à démarrer votre application.
Dans ce chapitre, nous verrons comment démarrer un exemple simple en utilisant NHibernate. Nous allons construire unsimple console application. Pour créer une application console, nous utiliserons Visual Studio 2015, qui contient toutes les fonctionnalités dont vous avez besoin pour créer, tester votre application à l'aide du package NHibernate.
Voici les étapes pour créer un projet à l'aide des modèles de projet disponibles dans Visual Studio.
Step 1 - Ouvrez le studio visuel et cliquez sur l'option de menu Fichier → Nouveau → Projet.
Step 2 - Une nouvelle boîte de dialogue Projet s'ouvre.
Step 3 - Dans le volet gauche, sélectionnez Modèles → Visual C # → Windows.
Step 4 - Dans le volet central, sélectionnez Application console.
Step 5 - Entrez le nom du projet, «NHibernateDemoApp», dans le champ Nom et cliquez sur OK pour continuer.
Step 6 - Une fois le projet créé par Visual Studio, vous verrez un certain nombre de fichiers affichés dans la fenêtre Explorateur de solutions.
Comme vous savez que nous avons créé un projet d'application console simple, nous devons maintenant inclure le package NHibernate dans notre projet console.
Allez dans le menu Outils et sélectionnez NuGet Package Manager → Package Manager Console, cela ouvrira la fenêtre de Package Manager Console.
Spécifiez la commande indiquée ci-dessus Package Manager Consoleet appuyez sur Entrée, il téléchargera toutes les dépendances NHibernate et créera des références à tous les assemblys requis. Une fois l'installation terminée, vous verrez le message comme indiqué dans l'image suivante.
Maintenant que NHibernate est ajouté, nous pouvons maintenant commencer l'implémentation. Nous allons donc commencer par cartographier un très simpletable appelé Student, qui a simplement une clé primaire entière appelée ID et une colonne FirstName et LastName.
Nous avons besoin d'une classe pour représenter cet élève, alors créons une nouvelle classe appelée Etudiant en cliquant avec le bouton droit sur le projet dans l'explorateur de solutions, puis sélectionnez Ajouter → Classe qui ouvrira la boîte de dialogue Ajouter un nouvel élément.
Entrer Student.csdans le champ de nom, cliquez sur le bouton Ajouter. Dans cette classe Student, nous devons avoir notre clé primaire entière appelée ID, et nous devons créer cette chaîne,FirstName et LastName champs comme indiqué dans l'implémentation complète suivante de la classe Student.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NHibernateDemoApp {
class Student {
public virtual int ID { get; set; }
public virtual string LastName { get; set; }
public virtual string FirstMidName { get; set; }
}
}
Lorsqu'il s'agit de modèles dans l'application NHibernate, il est plus facile de rendre tous vos champs virtuels. C'est donc notre modèle NHibernate simple que nous utiliserons et le mapperons à la base de données principale.
Passons maintenant à la méthode Main dans la classe Program et créons un nouvel objet de configuration NHibernate.
La première chose que nous devons fournir est le connection string. Il s'agit d'une chaîne de connexion spécifique à la base de données et le moyen le plus simple de trouver la chaîne de connexion est de faire un clic droit sur la base de données dansSQL Server Object Explorer et sélectionnez Propriétés.
Cela ouvrira la fenêtre Propriétés, maintenant faites défiler vers le bas et vous verrez le champ Chaîne de connexion dans la fenêtre Propriétés.
Copiez la chaîne de connexion et spécifiez dans votre code. Voici l'implémentation de la méthode Main dans laquelle nous avons besoin d'une configuration pour NHibernate.
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
//perform database logic
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Après la chaîne de connexion, nous devons fournir un pilote, qui est le SQLClientDriver puis nous devons également lui fournir un dialecte, quelle version de SQL Server, et nous allons utiliser MS SQL 2008.
NHibernate sait désormais se connecter à la base de données. L'autre chose que nous devons faire est de lui fournir une liste de modèles que nous allons cartographier.
Nous pouvons le faire en ajoutant un assembly, donc en spécifiant le Assembly.GetExecutingAssemblyet c'est là que le programme trouvera les fichiers de mappage. Les fichiers de mappage indiquent à NHibernate comment passer des classes C # aux tables de base de données.
SessionFactory compile toutes les métadonnées nécessaires à l'initialisation de NHibernate. SessionFactory peut être utilisé pour créer des sessions, qui sont à peu près analogues aux connexions de base de données. La manière appropriée est donc de l'utiliser dans le bloc using. je peux direvar session équivaut à sessionFactory.OpenSession et je vais vouloir faire cela dans le cadre de sa transaction.
Une fois la session ouverte, nous pouvons dire à la session de commencer une nouvelle transaction et nous pouvons ensuite effectuer une logique ici. Exécutez donc une logique de base de données et validez finalement cette transaction.
Dans ce chapitre, nous couvrirons quelques basic mappinget vous savez que depuis le dernier chapitre, nous avons la table de base de données ainsi que la définition de la classe C #. Nous avons maintenant besoin d'un mappage qui explique comment traduire de C # à la base de données et inversement.
Alors allons-y et ajoutons un nouveau fichier XML en faisant un clic droit sur le projet dans l'explorateur de solutions et sélectionnez Ajouter → Nouvel élément ...
Entrer Student.hbm.xmldans le champ du nom. Nous devons spécifier un assemblage par défaut qui seraNHibernateDemoAppet spécifiez également un espace de noms par défaut. Cela raccourcit simplement beaucoup d'autres définitions de type que nous allons créer dans ce fichier.
Voici l'implémentation dans le fichier XML -
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2"
assembly = "NHibernateDemoApp" namespace = "NHibernateDemoApp">
<class name = "Student">
<id name = "ID">
<generator class = "native"/>
</id>
<property name = "LastName"/>
<property name = "FirstMidName"/>
</class>
</hibernate-mapping>
La prochaine chose dont nous avons besoin pour définir une classe; cette classe va être notreStudent class. Ensuite, nous devons indiquer à NHibernate le nom de l'id, qui est ID et je dois également dire à NHibernate comment générer des ID, donc notre générateur sera de type natif.
Le générateur de type natif signifie que dans une base de données comme SQL Server, il va utiliser la colonne d'identité, le type d'identité.
La prochaine chose que nous devons faire est de donner les noms des propriétés. Donc, ajoutez deux autres propriétés pour le FirstName et le LastName.
Maintenant, nous lisons ces fichiers de mappage à partir de l'assembly. Donc, la meilleure façon de procéder est d'avoir cesHBM filescuit dans votre assemblage. Nous pouvons le faire en définissant simplement une propriété.
Maintenant, faites un clic droit sur le projet dans l'explorateur de solutions et sélectionnez Propriétés, vous verrez le Build Action field dans lequel le contenu est sélectionné par défaut.
Sélectionnez la ressource intégrée dans la liste déroulante.
Donc, cela intègre en fait ce fichier XML à l'intérieur du NHibernateDemoApp Assemblée.
Dans ce chapitre, nous couvrirons les bases CRUD operations. Maintenant que notre système est prêt à démarrer, comme nous avons implémenté avec succès notre classe de domaine Student, nous avons également défini les fichiers de mappage et configuré NHibernate. Nous pouvons maintenant utiliser certaines requêtes pour effectuer des opérations CRUD.
Créer des données
Comme vous pouvez le voir, nous n'avons pas de données dans notre table Student en NHibernateDemoDB base de données.
Donc, pour ajouter des données, nous devons effectuer le Add/Create fonctionnement comme indiqué ci-dessous.
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var student1 = new Student {
ID = 1,
FirstMidName = "Allan",
LastName = "Bommer"
};
var student2 = new Student {
ID = 2,
FirstMidName = "Jerry",
LastName = "Lewis"
};
session.Save(student1);
session.Save(student2);
tx.Commit();
}
Console.ReadLine();
}
Comme vous pouvez le voir, nous avons créé deux étudiants, puis appelons la méthode Save () du OpenSession puis appelez le Commit () du BeginTransaction. Voici l'implémentation complète dansProgram.cs fichier
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var student1 = new Student {
ID = 1,
FirstMidName = "Allan",
LastName = "Bommer"
};
var student2 = new Student {
ID = 2,
FirstMidName = "Jerry",
LastName = "Lewis"
};
session.Save(student1);
session.Save(student2);
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Maintenant, exécutons cette application, puis allons dans l'explorateur d'objets SQL Server et actualisons votre base de données. Vous verrez que les deux étudiants ci-dessus sont maintenant ajoutés à la table Student dans la base de données NHibernateDemoDB.
Lire les données de la table des étudiants
Vous pouvez voir que nous avons maintenant deux enregistrements dans notre table des étudiants. Pour lire ces enregistrements à partir de la table, nous devons appeler leCreateCriteria() d'OpenSession comme indiqué dans le code suivant.
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var students = session.CreateCriteria<Student>().List<Student>();
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}",
student.ID,student.FirstMidName, student.LastName);
}
tx.Commit();
}
Console.ReadLine();
}
Donc, si vous voulez la liste des enregistrements, nous pouvons simplement dire liste de type Student.
Maintenant, utilisez le foreach à travers tous les élèves et dites imprimer la pièce d'identité, FirstMidName et LastNamesur la console. Maintenant, exécutons à nouveau cette application et vous verrez la sortie suivante dans la fenêtre de la console.
1 Allan Bommer
2 Jerry Lewis
Vous pouvez également récupérer n'importe quel enregistrement en spécifiant l'ID dans le Get() méthode d'OpenSession à l'aide du code suivant.
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var students = session.CreateCriteria<Student>().List<Student>();
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID,
student.FirstMidName, student.LastName);
}
var stdnt = session.Get<Student>(1);
Console.WriteLine("Retrieved by ID");
Console.WriteLine("{0} \t{1} \t{2}", stdnt.ID,
stdnt.FirstMidName, stdnt.LastName);
tx.Commit();
}
Console.ReadLine();
}
Maintenant, lorsque vous exécutez votre application, vous verrez la sortie suivante.
1 Allan Bommer
2 Jerry Lewis
Retrieved by ID
1 Allan Bommer
Mettre à jour l'enregistrement
Pour mettre à jour l'enregistrement dans la table, nous devons d'abord récupérer cet enregistrement particulier, puis mettre à jour cet enregistrement en appelant le Update() méthode d'OpenSession comme indiqué dans le code suivant.
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var students = session.CreateCriteria<Student>().List<Student>();
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID,
student.FirstMidName, student.LastName);
}
var stdnt = session.Get<Student>(1);
Console.WriteLine("Retrieved by ID");
Console.WriteLine("{0} \t{1} \t{2}", stdnt.ID, stdnt.FirstMidName, stdnt.LastName);
Console.WriteLine("Update the last name of ID = {0}", stdnt.ID);
stdnt.LastName = "Donald";
session.Update(stdnt);
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID,
student.FirstMidName, student.LastName);
}
tx.Commit();
}
Console.ReadLine();
}
Maintenant, lorsque vous exécutez votre application, vous verrez la sortie suivante.
1 Allan Bommer
2 Jerry Lewis
Retrieved by ID
1 Allan Bommer
Update the last name of ID = 1
Fetch the complete list again
1 Allan Donald
2 Jerry Lewis
Comme vous pouvez le voir, LastName d'ID égal à 1 est mis à jour de Bommer à Donald.
Supprimer l'enregistrement
Pour supprimer un enregistrement de la table, nous devons d'abord récupérer cet enregistrement particulier, puis supprimer cet enregistrement en appelant le Delete() méthode d'OpenSession comme indiqué dans le code suivant.
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var students = session.CreateCriteria<Student>().List<Student>();
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID,
student.FirstMidName, student.LastName);
}
var stdnt = session.Get<Student>(1);
Console.WriteLine("Retrieved by ID");
Console.WriteLine("{0} \t{1} \t{2}", stdnt.ID, stdnt.FirstMidName, stdnt.LastName);
Console.WriteLine("Delete the record which has ID = {0}", stdnt.ID);
session.Delete(stdnt);
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstMidName,
student.LastName);
}
tx.Commit();
}
Console.ReadLine();
}
Maintenant, lorsque vous exécutez votre application, vous verrez la sortie suivante.
1 Allan Donald
2 Jerry Lewis
Retrieved by ID
1 Allan Bommer
Delete the record which has ID = 1
Fetch the complete list again
2 Jerry Lewis
Comme vous pouvez le voir, l'enregistrement dont l'ID est égal à 1 n'est plus disponible dans la base de données. Vous pouvez également voir la base de données dans l'explorateur d'objets SQL Server.
Dans ce chapitre, nous allons comprendre comment tous les enregistrements de la base de données sont retrieved, updated, created, and deleted et comment exactement ces requêtes sont effectuées?
Pour comprendre tout cela, nous pouvons simplement ajouter une option dans notre configuration, qui enregistre le SQL dans la console. Voici l'instruction simple qui enregistrera la requête SQL -
x.LogSqlInConsole = true;
Maintenant, nous avons deux enregistrements dans notre table Student dans la base de données NHibernateDemoDB. Récupérons tous les enregistrements de la base de données comme indiqué dans le code suivant.
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
Console.WriteLine("\nFetch the complete list again\n");
var students = session.CreateCriteria<Student>().List<Student>();
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstMidName,
student.LastName);
}
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Alors allons-y et exécutons à nouveau cette application, et vous verrez la sortie suivante -
NHibernate: SELECT this_.ID as ID0_0_, this_.LastName as LastName0_0_,
this_.FirstMidName as FirstMid3_0_0_ FROM Student this_
Fetch the complete list again
3 Allan Bommer
4 Jerry Lewis
Comme vous pouvez le voir, le select clauseétant envoyé à la base de données, il s'agit en fait d'une clause similaire qui récupérera l'ID, le FirstMidName et le LastName. Donc, tout cela est envoyé à la base de données et y est traité plutôt que d'avoir beaucoup d'enregistrements ramenés sur votre serveur et traités côté serveur.
NHibernate Profiler
Une autre façon de voir ces résultats consiste à utiliser NHibernate Profiler. NHibernate Profiler est un outil commercial, mais est-il très utile pour travailler avec les applications NHibernate. Vous pouvez facilement installer NHibernate Profiler dans votre application à partir de NuGet.
Allons à la console NuGet Manager à partir du menu Outils en sélectionnant NuGet Package Manager → Package Manager Console. Cela ouvrira la fenêtre de la console du gestionnaire de package. Entrez la commande suivante et appuyez sur Entrée.
PM> install-package NHibernateProfiler
Il installera tous les binaires requis pour NHibernate Profiler, une fois qu'il sera installé avec succès, vous verrez le message suivant.
Vous verrez également que NHibernate Profiler est lancé, une fois installé. Il faudra une licence pour l'utiliser, mais à des fins de démonstration, nous pouvons utiliser la version d'essai de 30 jours de NHibernate Profiler.
Désormais, NHibernate Profiler est optimisé pour fonctionner avec les applications Web et vous verrez qu'il a ajouté App_Start folderdans l'explorateur de solutions. Pour garder tout cela simple, supprimez le dossier App_Start et vous observerez également qu'une instruction est ajoutée au début de la méthode Main dans la classe Program.
App_Start.NHibernateProfilerBootstrapper.PreStart();
Supprimez également cette instruction et ajoutez simplement un simple appel NHibernateProfiler.Initialize comme indiqué dans le code suivant.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()){
var students = session.CreateCriteria<Student>().List<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstMidName,
student.LastName);
}
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Désormais, lorsque vous exécutez l'application, elle enverra des données à l'application NHibernate Profiler.
Vous pouvez voir ici, nous avons un bel affichage qui montre que nous avons commencé la transaction, ce que le SQL fait à la base de données dans un bon format.
Ceci est donc très utile pour déterminer ce qui se passe exactement dans votre application NHibernate. Cela devient incroyablement utile une fois que l'application atteint un certain niveau de complexité, où vous avez besoin de quelque chose de plus comme un SQL Profiler, mais avec la connaissance de NHibernate.
Dans ce chapitre, nous ajouterons IntelliSense à nos fichiers de mappage NHibernate (*.hbm.xml files). Comme vous l'avez observé lors du mappage de la classe Student du domaine, nous n'avons actuellement pas IntelliSense disponible. C'est très utile d'avoir leXML schemasdisponible. Ainsi, dans ce chapitre, vous comprendrez comment ajouter IntelliSense dans Visual Studio pour ces fichiers XML NHibernate.
Ouvrez le fichier de mappage et vous verrez que l'option de menu XML apparaît dans le menu principal.
Sélectionnez l'option de menu XML → Schémas… et la boîte de dialogue Schémas XML s'affiche.
Sélectionnez le bouton Ajouter… qui se trouve en haut à droite de la boîte de dialogue, qui ouvre la boîte de dialogue de fichier. Allez maintenant à lapackages folder, qui se trouve dans le dossier Solution de votre projet et vous verrez les différents packages inclus dans votre projet.
Maintenant, double-cliquez sur NHibernate.4.*** folder et vous verrez les deux fichiers de schéma (* .xsd) ou fichiers de définition de schéma XML qui définissent la configuration et le mappage de NHibernate.
Sélectionnez ces deux fichiers de schéma et cliquez sur le bouton Ouvrir.
Vous pouvez voir que les schémas NHibernate sont ajoutés dans la boîte de dialogue XML Schemas. Cliquez sur le bouton OK. Maintenant, commençons une nouvelle balise de propriété et vous verrez que nous avons complet IntelliSense ici.
IntelliSense est désormais disponible pour vous, ce qui vous permet de gagner beaucoup de temps lors du mappage objet-relationnel.
Dans ce chapitre, nous couvrirons les types de données cartographiques. Le mappage des entités est simple, les classes d'entités sont toujours mappées aux tables de base de données en utilisant<class>, <subclass>, and <joined-subclass>éléments de cartographie. Les types de valeur ont besoin de quelque chose de plus, c'est là que les types de mappage sont requis.
NHibernate est capable de cartographier une grande variété de types de données. Voici la liste des types de données les plus courants pris en charge.
Type de mappage | Type .NET | System.Data.DbType |
---|---|---|
Int16 | System.Int16 | DbType.Int16 |
Int32 | System.Int32 | DbType.Int32 |
Int64 | System.Int64 | DbType.Int64 |
Célibataire | Système unique | DbType.Single |
Double | Système.Double | DbType.Double |
Décimal | System.Decimal | DbType.Decimal |
Chaîne | System.String | DbType.String |
AnsiString | System.String | DbType.AnsiString |
Octet | System.Byte | DbType.Byte |
Carboniser | System.Char | DbType.StringFixedLength: un caractère |
AnsiChar | System.Char | DbType.AnsiStringFixedLength: un caractère |
Booléen | System.Boolean | DbType.Boolean |
Guid | Système.Guid | DbType.Guid |
PersistentEnum | System.Enum (une énumération) | DbType pour la valeur sous-jacente |
Vrai faux | System.Boolean | DbType.AnsiStringFixedLength: «T» ou «F» |
Oui Non | System.Boolean | DbType.AnsiStringFixedLength: «Y» ou «N» |
DateHeure | DateHeure | DbType.DateTime: ignore les millisecondes |
Les tiques | System.DateTime | DbType.Int64 |
TimeSpan | System.TimeSpan | DbType.Int64 |
Horodatage | System.DateTime | DbType.DateTime - aussi spécifique que la base de données le prend en charge |
Binaire | System.Byte [] | DbType.Binary |
BinaryBlob | System.Byte [] | DbType.Binary |
StringClob | System.String | DbType.String |
Sérialisable | Tout objet System.Object marqué avec SerializableAttribute | DbType.Binary |
CultureInfo | System.Globalization.CultureInfo | DbType.String: cinq caractères pour la culture |
Type | Type de système | DbType.String contenant le nom qualifié d'assembly |
Le tableau ci-dessus explique en détail les pointeurs mentionnés ci-dessous.
Tout, des types numériques simples aux chaînes, qui peuvent être mappées de différentes manières en utilisant varchars, chars etc. ainsi que des blobs de chaînes et toute la variété de types pris en charge par les bases de données.
Il est également capable de cartographier Booleans, à la fois vers des champs utilisant des zéros et des uns, des champs de caractères contenant vrai, faux ou T et F.
Il existe une grande variété de façons de définir la façon dont cela correspond aux valeurs booléennes principales de la base de données.
Nous pouvons gérer la cartographie de DateTime, incluant et excluant les décalages de fuseau horaire, l'heure d'été, etc.
Nous pouvons également cartographier enumerations; nous pouvons les mapper à des chaînes ou à leurs valeurs numériques sous-jacentes.
Jetons un coup d'œil à un exemple simple dans lequel nous avons les mêmes noms de propriétés à la fois dans la base de données et dans la classe Student.
Modifions maintenant le FirstMidName en FirstName dans la classe étudiant, où nous ne changerons pas la colonne FirstMidName, mais nous verrons comment dire à NHibernate know d'effectuer cette conversion. Voici la classe étudiante mise à jour.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NHibernateDemoApp {
class Student {
public virtual int ID { get; set; }
public virtual string LastName { get; set; }
public virtual string FirstName { get; set; }
}
}
Voici l'implémentation du fichier de mappage NHibernate.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemoApp"
namespace = "NHibernateDemoApp">
<class name = "Student">
<id name = "ID">
<generator class = "native"/>
</id>
<property name = "LastName"/>
<property name = "FirstName" column = "FirstMidName" type = "String"/>
</class>
</hibernate-mapping>
Dans cet exemple, supposons que le champ FirstName est une chaîne .NET et que la colonne FirstMidName est un SQL nvarchar. Maintenant, pour dire à NHibernate comment effectuer cette conversion, définissez le nom égal àFirstName et colonne égale à FirstMidName et spécifiez le type de mappage égal à String, qui est approprié pour cette conversion particulière.
Ce qui suit est un Program.cs implémentation de fichier.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var students = session.CreateCriteria<Student>().List<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2}", student.ID, student.FirstName,
student.LastName);
}
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Maintenant, lorsque vous exécutez votre application, vous verrez la sortie suivante.
NHibernate: SELECT this_.ID as ID0_0_, this_.LastName as LastName0_0_,
this_.FirstMidName as FirstMid3_0_0_ FROM Student this_
Fetch the complete list again
3 Allan Bommer
4 Jerry Lewis
Comme vous pouvez le voir, il a mappé le nom de propriété différent au nom de la colonne dans la base de données.
Jetons un coup d'œil à un autre exemple dans lequel nous ajouterons une autre propriété dans la classe Student de enumtype. Voici l'implémentation de la classe Student.
using System;
using System.Collections.Generic;
using System.Linq; using System.Text;
using System.Threading.Tasks;
namespace NHibernateDemoApp {
class Student {
public virtual int ID { get; set; }
public virtual string LastName { get; set; }
public virtual string FirstName { get; set; }
public virtual StudentAcademicStanding AcademicStanding { get; set; }
}
public enum StudentAcademicStanding {
Excellent,
Good,
Fair,
Poor,
Terrible
}
}
Comme vous pouvez le voir, l'énumération a une variété de valeurs différentes qu'elle peut éventuellement avoir, telles que Excellent, Bon, Passable, Pauvre et Terrible.
En passant au fichier de mappage, vous pouvez voir que chacune de ces propriétés est répertoriée dans le fichier de mappage, y compris le fichier nouvellement ajouté AcademicStanding propriété.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2"
assembly = "NHibernateDemoApp" namespace = "NHibernateDemoApp">
<class name = "Student">
<id name = "ID">
<generator class = "native"/>
</id>
<property name = "LastName"/>
<property name = "FirstName" column = "FirstMidName" type = "String"/>
<property name = "AcademicStanding"/>
</class>
</hibernate-mapping>
Maintenant, nous devons également changer la base de données, alors allez dans l'Explorateur d'objets SQL Server et cliquez avec le bouton droit sur la base de données et sélectionnez l'option Nouvelle requête….
Il ouvrira l'éditeur de requête, puis spécifiera la requête ci-dessous.
DROP TABLE [dbo].[Student]
CREATE TABLE [dbo].[Student] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[LastName] NVARCHAR (MAX) NULL,
[FirstMidName] NVARCHAR (MAX) NULL,
[AcademicStanding] NCHAR(10) NULL,
CONSTRAINT [PK_dbo.Student] PRIMARY KEY CLUSTERED ([ID] ASC)
);
Cette requête supprimera d'abord la table Student existante, puis créera une nouvelle table.
Cliquez sur l'icône Exécuter comme indiqué ci-dessus. Une fois la requête exécutée avec succès, vous voyez un message.
Développez la base de données et la liste déroulante Table, puis cliquez avec le bouton droit sur la table Student et sélectionnez View Designer.
Maintenant, vous verrez la table nouvellement créée, qui a également la nouvelle propriété AcademicStanding.
Ajoutons deux enregistrements comme indiqué ci-dessous Program.cs fichier.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var student1 = new Student {
ID = 1,
FirstName = "Allan",
LastName = "Bommer",
AcademicStanding = StudentAcademicStanding.Excellent
};
var student2 = new Student {
ID = 2,
FirstName = "Jerry",
LastName = "Lewis",
AcademicStanding = StudentAcademicStanding.Good
};
session.Save(student1);
session.Save(student2);
var students = session.CreateCriteria<Student>().List<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
student.FirstName, student.LastName, student.AcademicStanding);
}
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Maintenant, exécutons votre application et vous verrez la sortie suivante sur la fenêtre de votre console.
Fetch the complete list again
1 Allan Bommer Excellent
2 Jerry Lewis Good
Examinons maintenant la base de données en faisant un clic droit sur la table des étudiants.
Sélectionnez Afficher les données et vous verrez les deux enregistrements dans la table des élèves, comme illustré dans la capture d'écran suivante.
Vous pouvez voir que deux enregistrements sont ajoutés et Allan a AcademicStanding 0 et Jerry a AcademicStanding 1. C'est parce que dans .Net la première valeur d'énumération par défaut a 0, ce qui est Excellent si vous regardez StudentAcademicStanding. Alors que dans le fichier Student.cs Good est le deuxième, il a donc une valeur de 1.
Dans ce chapitre, nous examinerons la configuration de NHibernate. Nous avons différentes manières de configurer NHibernate. Il se divise en deux groupes principaux
- Configuration basée sur XML
- Configuration basée sur le code
Configuration basée sur le code
La configuration basée sur le code est intégrée à NHibernate. Il a été introduit autour du NHibernate 3 et nous avons utilisé jusqu'à présent la configuration des bases de code.
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
Toutes les configurations sont spécifiées dans le code C #. Vous pouvez voir ici que nous avons notre nouvel objet de configuration, puis nous utilisonsloquacious configurationqui a été introduit avec NHibernate 3.1 pour configurer la base de données. Quelle chaîne de connexion nous utilisons, à quelle base de données nous nous connectons et le dialecte à utiliser. Nous ajoutons également notre assemblage de mappage directement ici.
Configuration basée sur XML
Si vous utilisez une configuration XML, vous pouvez utiliser un hibernate.cfg.xml , qui est juste un fichier xml autonome utilisant le schéma NHibernate, ou vous pouvez intégrer cette configuration spécifique NHibernate à l'intérieur de votre application ou web.cfg. Le nom hibernate.cfg.xml est par défaut, mais nous pouvons également utiliser un nom arbitraire pour ce fichier xml.
Examinons la configuration basée sur XML en ajoutant un nouveau fichier xml au projet NHibernateDemoApp et appelons-le hibernate.cfg.xml.
Entrez les informations suivantes dans le fichier hibernate.cfg.xml.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-configuration xmlns = "urn:nhibernate-configuration-2.2">
<session-factory>
<property name = "connection.connection_string">
Data Source = asia13797\\sqlexpress;
Initial Catalog = NHibernateDemoDB;
Integrated Security = True;
Connect Timeout = 15;
Encrypt = False;
TrustServerCertificate = False;
ApplicationIntent = ReadWrite;
MultiSubnetFailover = False;
</property>
<property name = "connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name = "dialect">
NHibernate.Dialect.MsSql2008Dialect
</property>
<mapping assembly = "NHibernateDemoApp"/>
</session-factory>
</hibernate-configuration>
Comme vous pouvez le voir dans le fichier xml ci-dessus, nous avons spécifié la même configuration que celle mentionnée dans le C #.
Maintenant, commentons cette configuration à partir du fichier Program.cs et appelons simplement le Configure() méthode, qui chargera le hibernate.cfg.xml fichier comme indiqué ci-dessous.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
//cfg.DataBaseIntegration(x =>
//{
// x.ConnectionString = "Data Source = asia13797;\\sqlexpress
Initial Catalog = NHibernateDemoDB;
Integrated Security = True;
Connect Timeout = 15;
Encrypt =False;
TrustServerCertificate = False;
ApplicationIntent = ReadWrite;
MultiSubnetFailover = False";
// x.Driver<SqlClientDriver>();
// x.Dialect<MsSql2008Dialect>();
// x.LogSqlInConsole = true;
//});
//cfg.AddAssembly(Assembly.GetExecutingAssembly());
cfg.Configure();
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var students = session.CreateCriteria<Student>().List<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
student.FirstName, student.LastName, student.AcademicStanding);
}
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Exécutons à nouveau votre application et vous verrez le même résultat.
Fetch the complete list again
1 Allan Bommer Excellent
2 Jerry Lewis Good
Dans ce chapitre, nous expliquerons comment remplacer la configuration de NHibernate. Il y a juste quelques points à garder à l'esprit.
Tout d'abord, la configuration dans NHibernate est additive.
Ainsi, vous ne devez pas simplement utiliser un seul fichier xml ou vous ne devez pas simplement utiliser la configuration basée sur le code ou NHibernate fluide.
Vous pouvez mélanger et assortir toutes ces méthodes en fonction de la façon dont vous souhaitez configurer votre application.
Le point important à retenir est que, enfin, la configuration gagne.
Dans l'exemple suivant, vous pouvez voir que nous créons notre objet de configuration, le configurons à l'aide de la configuration basée sur le code et enfin appelons le cfg.configure() méthode, qui charge le fichier hibernate.cfg.xml.
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
});
cfg.Configure();
Ainsi, tout ce qui se trouve à l'intérieur d'un hibernate.cfg.xml remplace les paramètres définis par la configuration basée sur le code.
En inversant ces deux processus, nous pouvons avoir les valeurs par défaut à l'intérieur de hibernate.cfg.xml, puis effectuer nos remplacements à l'intérieur d'une configuration basée sur du code.
Il n'y a rien qui exclut si vous utilisez une configuration basée sur le code et rien ne vous empêche d'utiliser le fichier hibernate.cfg.xml.
Jetons un coup d'œil à un exemple simple dans lequel nous remplacerons la configuration en utilisant un mélange de configuration basée sur xml et basée sur du code.
Déplaçons également la chaîne de connexion vers le app.config fichier en utilisant le code suivant.
<?xml version = "1.0" encoding = "utf-8" ?>
<configuration>
<startup>
<supportedRuntime version = "v4.0" sku = ".NETFramework,Version = v4.5" />
</startup>
<connectionStrings>
<add name = "default" connectionString = "Data Source =
asia13797\\sqlexpress;
Initial Catalog = NHibernateDemoDB;
Integrated Security = True;
Connect Timeout = 15;
Encrypt = False;
TrustServerCertificate = False;
ApplicationIntent = ReadWrite;
MultiSubnetFailover = False"/>
</connectionStrings>
</configuration>
La chaîne de connexion se trouve dans certains app.configfichier avec un nom par défaut. Maintenant, nous devons mentionner le nom par défaut dans le fichier hibernate.cfg.xml au lieu de la chaîne de connexion.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-configuration xmlns = "urn:nhibernate-configuration-2.2">
<session-factory>
<property name = "connection.connection_string">default</property>
<property name = "connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name = "dialect">
NHibernate.Dialect.MsSql2008Dialect
</property>
<mapping assembly = "NHibernateDemoApp"/>
</session-factory>
</hibernate-configuration>
Commentons la partie chaîne de connexion, le pilote et la partie dialecte de la configuration basée sur le code, car le programme le lira à partir du fichier hibernate.cfg.xml et du fichier LogSqlInConsole partie restera dans la configuration basée sur le code.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { //x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
//x.Driver<SqlClientDriver>();
//x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
});
cfg.Configure();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var students = session.CreateCriteria<Student>().List<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
student.FirstName, student.LastName, student.AcademicStanding);
}
tx.Commit();
}
Console.ReadLine();
}
}
}
}
Maintenant, lorsque vous exécutez l'application, vous verrez que le programme a lu le journal à partir de la configuration basée sur le code et d'autres configurations à partir du fichier hibernate.cfg.xml.
NHibernate: SELECT this_.ID as ID0_0_, this_.LastName as LastName0_0_,
this_.FirstMidName as FirstMid3_0_0_, this_.AcademicStanding as Academic4_0_0_ FROM
Student this_
Fetch the complete list again
1 Allan Bommer Excellent
2 Jerry Lewis Good
Alors maintenant, nous avons une partie de notre configuration à l'intérieur de notre hibernate.cfg.xml fichier, une partie se trouve à l'intérieur de la configuration basée sur le code et dépend de l'ordre d'appel basé sur le code par rapport à configure(), nous pouvons changer lequel d'entre eux l'emporte sur l'autre.
Dans ce chapitre, nous couvrirons la mise à jour de la taille des lots. La taille du lot vous permet decontrol the number of updates qui sortent en un seul aller-retour vers votre base de données pour les bases de données prises en charge.
La taille du lot de mise à jour a été définie par défaut à partir de NHibernate 3.2.
Mais si vous utilisez une version antérieure ou avez besoin de régler votre application NHibernate, vous devriez regarder la taille du lot de mise à jour, qui est un paramètre très utile qui peut être utilisé pour régler les performances de NHibernate.
En fait, la taille du lot contrôle le nombre d'insertions à pousser dans un groupe vers une base de données.
Pour le moment, seuls SQL Server et Oracle prennent en charge cette option car le fournisseur de base de données sous-jacent doit prendre en charge le traitement par lots des requêtes.
Jetons un coup d'œil à un exemple simple dans lequel nous avons défini la taille du lot à 10, ce qui insérera 10 enregistrements dans un ensemble.
cfg.DataBaseIntegration(x => {
x.ConnectionString = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
x.BatchSize = 10;
});
Voici l'implémentation complète dans laquelle 25 enregistrements seront ajoutés à la base de données.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver>SqlClientDriver<();
x.Dialect>MsSql2008Dialect>();
x.LogSqlInConsole = true;
x.BatchSize = 10;
});
//cfg.Configure();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
for (int i = 0; i < 25; i++) {
var student = new Student {
ID = 100+i,
FirstName = "FirstName"+i.ToString(),
LastName = "LastName" + i.ToString(),
AcademicStanding = StudentAcademicStanding.Good
};
session.Save(student);
}
tx.Commit();
var students = session.CreateCriteria<Student>().List<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,student.FirstName,
student.LastName, student.AcademicStanding);
}
}
Console.ReadLine();
}
}
}
}
Maintenant, exécutons votre application et vous voyez que toutes ces mises à jour passent au profileur NHibernate. Nous avons 26 allers-retours individuels vers la base de données 25 pour l'insertion et un pour récupérer la liste des étudiants.
Maintenant, pourquoi est-ce? La raison en est que NHibernate doit faire unselect scope identity car nous utilisons la stratégie de génération d'identifiant natif dans le fichier de mappage pour l'ID, comme indiqué dans le code suivant.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2"
assembly = "NHibernateDemoApp"
namespace = "NHibernateDemoApp">
<class name = "Student">
<id name = "ID">
<generator class = "native"/>
</id>
<property name = "LastName"/>
<property name = "FirstName" column = "FirstMidName" type = "String"/>
<property name = "AcademicStanding"/>
</class>
</hibernate-mapping>
Nous devons donc utiliser une méthode différente telle que la guid.combméthode. Si nous allons aller sur guid.comb, nous devons aller vers notre client et changer cela en unguid. Cela fonctionnera donc très bien. Passons maintenant du natif à guid.comb en utilisant le code suivant.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly =
"NHibernateDemoApp" namespace = "NHibernateDemoApp">
<class name = "Student">
<id name = "ID">
<generator class = "guid.comb"/>
</id>
<property name = "LastName"/>
<property name = "FirstName" column = "FirstMidName" type = "String"/>
<property name = "AcademicStanding"/>
</class>
</hibernate-mapping>
C'est donc la base de données qui est chargée de générer ces ID. La seule façon dont NHibernate peut savoir quel ID a été généré était de le sélectionner immédiatement après. Sinon, si nous avons créé un lot d'étudiants, il ne pourra pas faire correspondre l'ID de l'étudiant qui a été créé.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NHibernateDemoApp {
class Student {
public virtual Guid ID { get; set; }
public virtual string LastName { get; set; }
public virtual string FirstName { get; set; }
public virtual StudentAcademicStanding AcademicStanding { get; set; }
}
public enum StudentAcademicStanding {
Excellent,
Good,
Fair,
Poor,
Terrible
}
}
Nous avons juste besoin de mettre à jour notre base de données. Supprimons la table des étudiants et créons une nouvelle table en spécifiant la requête suivante, alors allez dans l'explorateur d'objets SQL Server et cliquez avec le bouton droit sur la base de données et sélectionnez leNew Query… Option.
Il ouvrira l'éditeur de requête, puis spécifiera la requête suivante.
DROP TABLE [dbo].[Student]
CREATE TABLE [dbo].[Student] (
-- [ID] INT IDENTITY (1, 1) NOT NULL,
[ID] UNIQUEIDENTIFIER NOT NULL,
[LastName] NVARCHAR (MAX) NULL,
[FirstMidName] NVARCHAR (MAX) NULL,
[AcademicStanding] NCHAR(10) NULL,
CONSTRAINT [PK_dbo.Student] PRIMARY KEY CLUSTERED ([ID] ASC)
);
Cette requête supprimera d'abord la table Student existante, puis créera une nouvelle table. Comme vous pouvez le voir, nous avons utiliséUNIQUEIDENTIFIER plutôt que d'utiliser une clé primaire entière comme ID.
Exécutez cette requête, puis accédez à la Designer view et vous verrez que maintenant l'ID est créé avec un identifiant unique comme indiqué dans l'image suivante.
Nous devons maintenant supprimer l'ID du fichier program.cs, lors de l'insertion des données, car maintenant il générera le guids pour cela automatiquement.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
x.BatchSize = 10;
});
//cfg.Configure();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
for (int i = 0; i > 25; i++) {
var student = new Student {
FirstName = "FirstName"+i.ToString(),
LastName = "LastName" + i.ToString(),
AcademicStanding = StudentAcademicStanding.Good
};
session.Save(student);
}
tx.Commit();
var students = session.CreateCriteria<Student>().List<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2} \t{3}", student.ID,
student.FirstName,student.LastName, student.AcademicStanding);
}
}
Console.ReadLine();
}
}
}
}
Maintenant, exécutez à nouveau l'application et jetez un œil au profileur NHibernate. Désormais, le profileur NHibernate, plutôt que de faire 26 allers-retours, n'en fera que quatre.
Il est inséré dix lignes dans le tableau, puis dix autres lignes, et plus tard les cinq autres. Et après la validation, il en a inséré un de plus pour récupérer tous les enregistrements.
Il l'a donc divisé en groupes de dix, du mieux qu'il peut.
Donc, si vous faites beaucoup d'insertions, cela peut considérablement améliorer les performances d'insertion dans votre application, car vous pouvez les regrouper.
En effet, NHibernate attribue ces guides lui-même en utilisant le guid.comb algorithme, et il n'a pas besoin de s'appuyer sur la base de données pour ce faire.
L'utilisation de la taille du lot est donc un excellent moyen de l'ajuster.
Dans ce chapitre, nous expliquerons comment le cachingfonctionne dans les applications NHibernate. Il a un support intégré pour la mise en cache. Cela ressemble à une fonctionnalité simple, mais en réalité, c'est l'une des fonctionnalités les plus complexes. Nous commencerons par le cache de premier niveau.
Cache de premier niveau
Ce mécanisme de cache est activé par défaut dans NHibernate et nous n'avons rien à faire pour travailler avec le cache. Pour comprendre cela, examinons un exemple simple, car vous pouvez voir que nous avons deux enregistrements dans notre base de données.
Maintenant, dans cet exemple, nous allons récupérer l'étudiant dont l'ID est 1 et nous utiliserons la même requête de session deux fois comme indiqué dans le code suivant.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cache;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.LogSqlInConsole = true;
x.BatchSize = 10;
});
//cfg.Configure();
cfg.Cache(c => {
c.UseMinimalPuts = true;
c.UseQueryCache = true;
});
cfg.SessionFactory().Caching .Through<HashtableCacheProvider>()
.WithDefaultExpiration(1440);
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()){
using (var tx = session.BeginTransaction()) {
var studentUsingTheFirstQuery = session.Get<Student>(1);
var studentUsingTheSecondQuery = session.Get<Student>(1);
}
Console.ReadLine();
}
}
}
}
Maintenant, exécutons cette application et voyons le résultat dans NHibernate Profiler.
Vous serez surpris de voir que NHibernate ne déclenche qu'une seule requête. C'est ainsi que NHibernate utilise le cache de premier niveau. Lorsque la première requête est exécutée, NHibernate a mis en cache l'étudiant avec l'ID = 1 dans son cache de premier niveau.
Ainsi, lorsque la deuxième requête est exécutée, NHibernate recherche d'abord l'entité Student du cache de premier niveau avec ID = 1, s'il trouve cette entité, alors NHibernate le sait, il n'est pas nécessaire de lancer une autre requête pour récupérer à nouveau le même objet employé. .
Dans ce chapitre, nous parlerons des composants de mappage. Dans NHibernate,component is a value object. Il n'a pas d'identité propre.
Un exemple de ceci serait un objet d'argent, un sac à main ou un portefeuille pourrait contenir de l'argent, mais l'identité exacte de cet argent n'a pas d'importance.
Il n'a pas sa propre clé primaire, mais les composants eux-mêmes sont persistants dans la même table que l'objet propriétaire.
Jetons un coup d'œil à un exemple simple dans lequel un étudiant a une adresse, qui est un objet de Location class associé avec.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NHibernateDemoApp {
class Student {
public virtual int ID { get; set; }
public virtual string LastName { get; set; }
public virtual string FirstName { get; set; }
public virtual StudentAcademicStanding AcademicStanding { get; set; }
public virtual Location Address { get; set; }
}
public class Location {
public virtual string Street { get; set; }
public virtual string City { get; set; }
public virtual string Province { get; set; }
public virtual string Country { get; set; }
}
public enum StudentAcademicStanding {
Excellent,
Good,
Fair,
Poor,
Terrible
}
}
Maintenant, nous devons également mettre à jour la base de données en exécutant la requête suivante, qui supprimera d'abord la table Student, puis créera une nouvelle table qui contiendra également une colonne pour la classe Location.
DROP TABLE [dbo].[Student]
CREATE TABLE [dbo].[Student] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[LastName] NVARCHAR (MAX) NULL,
[FirstMidName] NVARCHAR (MAX) NULL,
[AcademicStanding] NCHAR(10) NULL,
[Street] NVARCHAR (100) NULL,
[City] NVARCHAR (100) NULL,
[Province] NVARCHAR (100) NULL,
[Country] NVARCHAR (100) NULL,
CONSTRAINT [PK_dbo.Student] PRIMARY KEY CLUSTERED ([ID] ASC)
);
Maintenant, pour mapper les colonnes qui ne font pas directement partie de la classe Student, mais qui sont des propriétés de la classe Location et que l'objet de la classe Location est défini dans la classe Student. Nous avons besoin d'un composant pour le mapper correctement. Créons un composant dansstudent.hbm.xml fichier comme indiqué dans le code suivant.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2"
assembly = "NHibernateDemoApp" namespace = "NHibernateDemoApp">
<class name = "Student">
<id name = "ID">
<generator class = "native"/>
</id>
<property name = "LastName"/>
<property name = "FirstName" column = "FirstMidName" type = "String"/>
<property name = "AcademicStanding"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
</class>
</hibernate-mapping>
Ce composant est l'Adresse et il possède ces différentes propriétés. Avec ces informations, NHibernate en a maintenant assez pour pouvoir cartographier cela.
Voici maintenant le fichier Program.cs dans lequel un nouvel objet étudiant est créé et initialisé, puis enregistré dans la base de données. Il récupérera ensuite la liste de la base de données.
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cache;
using NHibernate.Caches.SysCache;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
using System;
using System.Linq;
using System.Reflection;
namespace NHibernateDemoApp {
class Program {
static void Main(string[] args) {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
cfg.DataBaseIntegration(x = > { x.ConnectionString = "Data Source +
Initial Catalog + Integrated Security + Connect Timeout + Encrypt +
TrustServerCertificate + ApplicationIntent + MultiSubnetFailover";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
});
cfg.AddAssembly(Assembly.GetExecutingAssembly());
var sefact = cfg.BuildSessionFactory();
using (var session = sefact.OpenSession()) {
using (var tx = session.BeginTransaction()) {
var student1 = new Student {
ID = 1,
FirstName = "Allan",
LastName = "Bommer",
AcademicStanding = StudentAcademicStanding.Poor,
Address = new Location {
Street = "123 Street",
City = "Lahore",
Province = "Punjab",
Country = "Pakistan"
}
};
session.Save(student1);
tx.Commit();
var students = session.Query<Student>().ToList<Student>();
Console.WriteLine("\nFetch the complete list again\n");
foreach (var student in students) {
Console.WriteLine("{0} \t{1} \t{2} \t{3} \t{4} \t{5} \t{6} \t{7}",
student.ID,
student.FirstName,
student.LastName,
student.AcademicStanding,
student.Address.Street,
student.Address.City,
student.Address.Province,
student.Address.Country
);
}
}
Console.ReadLine();
}
}
}
}
Nous pouvons maintenant exécuter cette application et NHibernate peut enregistrer ces valeurs dans la base de données. Lorsque vous exécutez l'application, vous verrez la sortie suivante.
Fetch the complete list again
2 Allan Bommer Poor 123 Street Lahore Punjab Pakistan
Voici les valeurs de la base de données.
Les composants nous permettent de séparer les colonnes qui se trouvent dans une table de base de données dans leur propre classe distincte.
L'autre chose à noter ici est que l'emplacement est une classe, ce n'est pas une entité.
C'est un objet de type valeur et il n'a pas sa propre clé primaire.
Il est enregistré dans la même table que l'étudiant qui le contient.
C'est pourquoi nous utilisons le composant ici.
Cela permet une grande flexibilité pour changer notre couche de classe, la façon dont nos classes sont définies par rapport à la disposition de notre base de données.
Dans ce chapitre, nous examinerons les relations dans NHibernate. Tournons notre attention sur la façon dont nous pouvons comprendre les relations dans NHibernate. Le moyen le plus simple est de réfléchir aux relations du point de vue de la base de données.
Nous allons d'abord créer une nouvelle application dans laquelle nous créerons des relations entre le client et les entités de commande.
La première relation que nous allons examiner est une relation de collection classique.
Nous avons un client avec une collection de commandes.
Il s'agit d'une relation un-à-plusieurs et elle est représentée dans la base de données par 2 tables et il y a un ID client sur la table des commandes et nous avons une relation de clé étrangère avec le client.
Nous devons d'abord créer une base de données et deux tables Client et Commande. Vous pouvez créer cela en spécifiant la requête suivante dans l'Explorateur SQL Server.
USE [master]
GO
CREATE DATABASE [NHibernateDemo]
GO
USE [NHibernateDemo]
GO
CREATE TABLE [dbo].[Customer](
[Id] [uniqueidentifier] NOT NULL,
[FirstName] [nvarchar](100) NOT NULL,
[LastName] [nvarchar](100) NOT NULL,
[Points] [int] NULL, [HasGoldStatus] [bit] NULL,
[MemberSince] [date] NULL,
[CreditRating] [nchar](20) NULL,
[AverageRating] [decimal](18, 4) NULL,
[Street] [nvarchar](100) NULL,
[City] [nvarchar](100) NULL,
[Province] [nvarchar](100) NULL,
[Country] [nvarchar](100) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
)
GO
CREATE TABLE [dbo].[Order](
[Id] [uniqueidentifier] NOT NULL,
[CustomerId] [uniqueidentifier] NULL,
[Ordered] [datetime] NULL,
[Shipped] [datetime] NULL,
[Street] [nvarchar](100) NULL,
[City] [nvarchar](100) NULL,
[Province] [nvarchar](100) NULL,
[Country] [nvarchar](100) NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
)
GO
Cela créera deux tables dans la base de données. L'image suivante montre la table des clients.
L'image suivante montre la table des commandes dans laquelle vous pouvez voir la relation de clé étrangère avec le client.
Nous devons définir la chaîne de connexion dans le app.config fichier, voici l'implémentation du fichier app.config.
<?xml version = "1.0" encoding = "utf-8" ?>
<configuration>
<connectionStrings>
<add name = "default" connectionString = "Data Source =
(localdb)\MSSQLLocalDB;Initial Catalog = NHibernateDemo;Integrated Security =
True;Connect Timeout = 30;Encrypt = False;TrustServerCertificate = False;
ApplicationIntent = ReadWrite;MultiSubnetFailover = False"/>
</connectionStrings>
</configuration>
Pour installer NHibernate dans votre application, exécutez la commande suivante dans la fenêtre NuGet Manager Console.
install-package NHibernate
Pour configurer la configuration NHibernate, nous devons définir la configuration dans hibernate.cfg.xml fichier comme indiqué dans le code suivant.
<xml version = "1.0" encoding = "utf-8" ?>
<hibernate-configuration xmlns = "urn:nhibernate-configuration-2.2">
<session-factory>
<property name = "connection.connection_string_name">default</property>
<property name = "connection.driver_class">
NHibernate.Driver.SqlClientDriver
</property>
<property name = "dialect">
NHibernate.Dialect.MsSql2008Dialect
</property>
<property name = "show_sql">true</property>
</session-factory>
</hibernate-configuration>
Dans cet exemple, nous allons travailler sur deux classes de domaine, Client et Commande.
Voici l'implémentation du fichier Customer.cs dans laquelle nous avons deux classes, l'une est la classe Customer et l'autre est la classe Location dans laquelle l'objet est utilisé comme adresse dans la classe Customer.
using System;
using System.Text;
using Iesi.Collections.Generic;
namespace NHibernateDemo {
public class Customer {
public Customer() {
MemberSince = DateTime.UtcNow;
Orders = new HashedSet<Order>();
}
public virtual Guid Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual double AverageRating { get; set; }
public virtual int Points { get; set; }
public virtual bool HasGoldStatus { get; set; }
public virtual DateTime MemberSince { get; set; }
public virtual CustomerCreditRating CreditRating { get; set; }
public virtual Location Address { get; set; }
public virtual ISet<Order> Orders { get; set; }
public virtual void AddOrder(Order order) { Orders.Add(order); order.Customer = this; }
public override string ToString() {
var result = new StringBuilder();
result.AppendFormat("{1} {2} ({0})\r\n\tPoints: {3}\r\n\tHasGoldStatus:
{4}\r\n\tMemberSince: {5} ({7})\r\n\tCreditRating: {6}\r\n\tAverageRating:
{8}\r\n", Id, FirstName, LastName, Points, HasGoldStatus, MemberSince,
CreditRating, MemberSince.Kind, AverageRating);
result.AppendLine("\tOrders:");
foreach(var order in Orders) {
result.AppendLine("\t\t" + order);
}
return result.ToString();
}
}
public class Location {
public virtual string Street { get; set; }
public virtual string City { get; set; }
public virtual string Province { get; set; }
public virtual string Country { get; set; }
}
public enum CustomerCreditRating {
Excellent,
VeryVeryGood,
VeryGood,
Good,
Neutral,
Poor,
Terrible
}
}
Voici le fichier de mappage Customer.hbm.xml dans laquelle la classe Customer est mappée à la table Customer.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
</class>
</hibernate-mapping>
Nous avons également une classe de commande et voici l'implémentation de Order.cs fichier.
using System; using Iesi.Collections.Generic;
namespace NHibernateDemo {
public class Order {
public virtual Guid Id { get; set; }
public virtual DateTime Ordered { get; set; }
public virtual DateTime? Shipped { get; set; }
public virtual Location ShipTo { get; set; }
public virtual Customer Customer { get; set; }
public override string ToString() {
return string.Format("Order Id: {0}", Id);
}
}
}
Relation plusieurs à un
Nous devons également mapper la classe Order à la table Order dans la base de données, voici donc l'implémentation du Order.hbm.xml fichier.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Order" table = "`Order`">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "Ordered"/>
<property name = "Shipped"/>
<component name = "ShipTo">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<!--<many-to-one name = "Customer" column = "CustomerId" cascade =
"save-update"/>-->
</class>
</hibernate-mapping>
Relation un-à-plusieurs
Ici, nous allons jeter un œil à une relation un-à-plusieurs, dans ce cas, entre le client et les commandes. Nous avons notre client ici, nous en créons un nouveau, et vous pouvez voir que la collection est initialisée avec la paire de commandes suivante.
private static Customer CreateCustomer() {
var customer = new Customer {
FirstName = "John",
LastName = "Doe",
Points = 100,
HasGoldStatus = true,
MemberSince = new DateTime(2012, 1, 1),
CreditRating = CustomerCreditRating.Good,
AverageRating = 42.42424242,
Address = CreateLocation()
};
var order1 = new Order {
Ordered = DateTime.Now
};
customer.AddOrder(order1);
var order2 = new Order {
Ordered = DateTime.Now.AddDays(-1),
Shipped = DateTime.Now,
ShipTo = CreateLocation()
};
customer.AddOrder(order2);
return customer;
}
Nous allons donc créer un nouveau client, puis l'enregistrer, après l'avoir sauvegardé, nous trouverons l'ID et le rechargerons dans une autre session dans la méthode Main comme indiqué dans le programme suivant.
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
Guid id;
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
id = newCustomer.Id;
tx.Commit();
}
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var reloaded = session.Load<Customer>(id);
Console.WriteLine("Reloaded:");
Console.WriteLine(reloaded);
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
Voici le complet Program.cs implémentation de fichier.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
Guid id;
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
id = newCustomer.Id;
tx.Commit();
}
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var reloaded = session.Load<Customer>(id);
Console.WriteLine("Reloaded:");
Console.WriteLine(reloaded);
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Customer CreateCustomer() {
var customer = new Customer {
FirstName = "John",
LastName = "Doe",
Points = 100,
HasGoldStatus = true,
MemberSince = new DateTime(2012, 1, 1),
CreditRating = CustomerCreditRating.Good,
AverageRating = 42.42424242,
Address = CreateLocation()
};
var order1 = new Order {
Ordered = DateTime.Now
};
customer.AddOrder(order1);
var order2 = new Order {
Ordered = DateTime.Now.AddDays(-1),
Shipped = DateTime.Now,
ShipTo = CreateLocation()
};
customer.AddOrder(order2);
return customer;
}
private static Location CreateLocation() {
return new Location {
Street = "123 Somewhere Avenue",
City = "Nowhere",
Province = "Alberta",
Country = "Canada"
};
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x =&ht; {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10; x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
Lorsque vous exécutez cette application, vous verrez la sortie suivante.
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (9b0fcf10-83f6-4f39-bda5-a5b800ede2ba)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Press <ENTER> to exit...
Comme vous pouvez le voir, au départ, le client a 2 commandes, mais lorsque nous le rechargeons, il n'y a aucune commande à voir. Si vous regardezcustomer.hbm.xmlfichier, vous pouvez voir ici que nous ne mappons pas la collecte des commandes réelles. Donc NHibernate n'en sait rien. Allons-y et ajoutons-le.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2"
assembly = "NHibernateDemo" namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
Il s'agit d'un ensemble et le nom de cette collection est «Commandes», qui est stocké dans une table appelée commande. Nous devons spécifier une clé qui est le nom de la clé étrangère ou pour trouver des commandes. Ces commandes sont identifiées ou appartiennent à un client via l'identifiant client. Et puis je dois noter qu'il s'agit d'une relation un-à-plusieurs et que c'est avec la classe d'ordre.
Nous devons également modifier légèrement la méthode principale en enregistrant les nouvelles commandes des clients dans la base de données ainsi que dans le programme suivant.
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
Guid id;
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
foreach (var order in newCustomer.Orders) {
session.Save(order);
}
id = newCustomer.Id;
tx.Commit();
}
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var reloaded = session.Load<Customer>(id);
Console.WriteLine("The orders were ordered by: ");
foreach (var order in reloaded.Orders) {
Console.WriteLine(order.Customer);
}
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit..."); Console.ReadLine();
}
Nous avons également spécifié quel client a commandé ce produit particulier. Nous devons donc créer une relation plusieurs-à-un pour relier cette commande à ce client.
Alors allons dans le Order.hbm.xml fichier et ajoutez plusieurs à un, puis nommez le champ client et la colonne avec l'ID client.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Order" table = "`Order`">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "Ordered"/>
<property name = "Shipped"/>
<component name = "ShipTo">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<many-to-one name = "Customer" column = "CustomerId"/>
</class>
</hibernate-mapping>
Exécutons à nouveau cette application et vous verrez maintenant la sortie suivante.
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (660a6f29-650e-4380-99e0-a5b800febbde)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 57314deb-e023-4e55-ac1e-a5b800febbe3
Order Id: fc065683-d5f5-484b-ae42-a5b800febbe3
The orders were ordered by:
John Doe (660a6f29-650e-4380-99e0-a5b800febbde)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 57314deb-e023-4e55-ac1e-a5b800febbe3
Order Id: fc065683-d5f5-484b-ae42-a5b800febbe3
John Doe (660a6f29-650e-4380-99e0-a5b800febbde)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 57314deb-e023-4e55-ac1e-a5b800febbe3
Order Id: fc065683-d5f5-484b-ae42-a5b800febbe3
Press <ENTER> to exit...
Dans ce chapitre, nous expliquerons comment représenter les collections. Il existe différents types de collections que nous pouvons utiliser dans NHibernate tels que -
- Lists
- Sets
- Bags
Maintenant, du point de vue .NET, nous traitons généralement des listes ou des structures de données très simples, des listes, des dictionnaires. .NET n'a pas une grande variété de types de collections différents. Alors pourquoi NHibernate a-t-il besoin de tous ces types différents? Cela revient vraiment à la base de données.
liste
Une liste est une collection ordonnée d'éléments qui ne sont pas nécessairement uniques.
Nous pouvons cartographier cela en utilisant le IList <T>.
Ainsi, même si nous pouvons classiquement avoir une liste d'adresses, et du point de vue de l'application, nous savons que les éléments sont uniques, rien dans la liste ne nous empêche d'insérer des éléments en double dans cette liste.
Ensemble
Un ensemble est une collection non ordonnée d'éléments uniques. Si vous essayez d'insérer 2 éléments en double dans un ensemble, cela lèvera une exception.
Il n'y a rien de spécifique dans NHibernate à ce sujet.
C'est juste un moyen pratique d'avoir une implémentation générique d'ensemble. Si vous utilisez .NET 4, vous pouvez utiliser le nouveauHashSet <T> pour les représenter, mais dans la plupart des applications NHibernate, nous représentons qu'il s'agit d'un ISet.
C'est un ordre non ordonné, si vous retirez une liste d'adresses d'une base de données ou d'une liste de commandes, vous ne savez pas dans quel ordre elles arrivent à moins que vous ne mettiez dans une clause Order by spécifique.
Donc, en général, les données que vous extrayez d'une base de données sont des ensembles.
Ce sont des collections uniques d'éléments qui ne sont pas ordonnés.
Sac
Une autre collection courante que nous verrons dans le monde des bases de données est un sac, qui ressemble à un ensemble, sauf qu'il peut avoir des éléments en double.
Dans le monde .NET, nous représentons cela par un IList.
Les ensembles sont probablement les plus courants, mais vous verrez également des listes et des sacs en fonction de votre application. Jetons un coup d'œil dans un ci-dessouscustomer.hbm.xml fichier du dernier chapitre dans lequel les ordres de set sont définis.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
Comme vous pouvez le voir, nous avons mappé la collection de commandes comme un ensemble. N'oubliez pas qu'un ensemble est une collection non ordonnée d'éléments uniques.
Maintenant, si vous regardez la classe Customer, vous verrez que la propriété Orders est définie avec un ISet comme indiqué dans le programme suivant.
public virtual ISet<Order> Orders { get; set; }
Maintenant, lorsque cette application est exécutée, vous verrez la sortie suivante.
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7
The orders were ordered by:
John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7
John Doe (1f248133-b50a-4ad7-9915-a5b8017d0ff1)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: c41af8f2-7124-42a7-91c5-a5b8017d0ff6
Order Id: 657f6bb0-1f42-45fc-8fc7-a5b8017d0ff7
Press <ENTER> to exit...
Si les éléments de la collection n'avaient pas besoin d'être uniques, si vous pouviez avoir plusieurs commandes avec la même clé primaire se produisant plusieurs fois dans cette collection, alors cela serait mieux mappé en tant que sac comme indiqué dans le programme suivant.
<bag name = "Orders" table = "`Order`">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</bag>
Maintenant, si vous exécutez cette application, vous obtiendrez une exception car si nous examinons la classe client, vous remarquerez que les commandes sont marquées comme un ISet dans le code C #.
Nous devrons donc également changer cela en IList, puis ici, nous aurions besoin de passer du HashSet à une liste dans le constructeur.
public class Customer {
public Customer() {
MemberSince = DateTime.UtcNow;
Orders = new List<Order>();
}
public virtual Guid Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual double AverageRating { get; set; }
public virtual int Points { get; set; }
public virtual bool HasGoldStatus { get; set; }
public virtual DateTime MemberSince { get; set; }
public virtual CustomerCreditRating CreditRating { get; set; }
public virtual Location Address { get; set; }
public virtual IList<Order> Orders { get; set; }
public virtual void AddOrder(Order order) { Orders.Add(order); order.Customer = this; }
public override string ToString() {
var result = new StringBuilder();
result.AppendFormat("{1} {2} ({0})\r\n\tPoints: {3}\r\n\tHasGoldStatus:
{4}\r\n\tMemberSince: {5} ({7})\r\n\tCreditRating: {6}\r\n\tAverageRating:
{8}\r\n", Id, FirstName, LastName, Points, HasGoldStatus, MemberSince,
CreditRating, MemberSince.Kind, AverageRating); result.AppendLine("\tOrders:");
foreach(var order in Orders) {
result.AppendLine("\t\t" + order);
}
return result.ToString();
}
}
Lorsque vous exécutez l'application, vous verrez le même comportement. Mais, maintenant, nous pouvons avoir une commande se produisant plusieurs fois dans la même collection.
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287
The orders were ordered by:
John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287
John Doe (fbde48f5-d620-4d1c-9a7f-a5b8017c3280)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 6dd7dbdb-354f-4c82-9c39-a5b8017c3286
Order Id: 9b3e2441-a81b-404d-9aed-a5b8017c3287
Press <ENTER> to exit...
Dans ce chapitre, nous expliquerons comment utiliser la fonction Cascade. Si vous avez un ensemble ou une collection d'articles ou une relation entre deux classes telles que notre client et notre commande et avez une relation de clé étrangère. Si nous supprimons le client par défaut, NHibernate ne fait rien aux objets enfants, donc ceux qui appartiennent à ce client et nous pourrions être des commandes orphelines.
Nous pourrions également violer les contraintes de clé étrangère, nous pouvons donc utiliser la notion de cascades.
Par défaut, NHibernate ne cascade pas les opérations sur les objets enfants.
La raison en est que vous pouvez avoir des relations telles qu'un client ayant une adresse de livraison par défaut et cette adresse de livraison est partagée avec de nombreux clients différents.
Vous ne voudriez donc pas nécessairement mettre en cascade cette relation parce que d'autres clients y font encore référence.
Donc toute la notion de cascades est de dire à NHibernate comment gérer ses entités enfants.
Il existe différentes options pour la mise en cascade, qui sont les suivantes -
none - qui est la valeur par défaut et cela signifie pas de cascade.
all - qui va enregistrer en cascade, mettre à jour et supprimer.
save-update - il va en cascade, enregistre et met à jour.
delete - il supprimera en cascade.
all-delete-orphan - c'est un système spécial qui est assez fréquemment utilisé et qui est le même que Tous sauf, s'il trouve des lignes Delete-orphan, il les supprimera également.
Vous pouvez spécifier la valeur par défaut dans votre hbm.xml afin que vous puissiez fournir une cascade par défaut sur cet élément de mappage Hibernate ou vous pouvez également le spécifier pour des collections et des relations spécifiques telles que plusieurs-à-un.
Jetons un coup d'œil à des exemples de cascades simples, corrigeons le problème dans le programme, où nous devons manuellement mettre en cascade la sauvegarde sur les commandes comme indiqué dans le code suivant.
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
foreach (var order in newCustomer.Orders) {
session.Save(order);
}
id = newCustomer.Id;
tx.Commit();
}
Dans l'extrait de code ci-dessus, vous pouvez voir que nous enregistrons manuellement toutes les commandes du client. Supprimons maintenant le code de cascade manuel dans lequel toutes les commandes sont enregistrées.
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
id = newCustomer.Id;
tx.Commit();
}
Nous devons spécifier l'option cascade dans customer.hbm.xml.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`" cascade = "all-delete-orphan">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
Désormais, les commandes appartiennent entièrement au client. Donc, si les clients étaient supprimés de la base de données, notre application souhaiterait supprimer toutes ces commandes, y compris celles qui auraient pu être orphelines.
Il finira par faire une suppression. Par cela, il indiquera supprimer de la table de commande, où l'ID client correspond au client que vous supprimez.
Vous pouvez donc effectivement mettre en cascade ces suppressions. Donc avec leAll, il effectuera des sauvegardes, des mises à jour et des suppressions.
Maintenant, lorsque vous exécutez cette application, vous verrez la sortie suivante.
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
The orders were ordered by:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
Press <ENTER> to exit...
Comme vous pouvez le voir, nous avons supprimé le code du programme qui est manuellement en cascade et notre application fonctionne toujours.
Donc, en fonction de votre relation, vous voudrez peut-être les mettre en cascade. Voyons maintenant une relation en cascade différente. Allons auOrder.hbm.xml fichier et nous pouvons mettre en cascade cette relation plusieurs-à-un.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Order" table = "`Order`">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "Ordered"/>
<property name = "Shipped"/>
<component name = "ShipTo">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<many-to-one name = "Customer" column = "CustomerId" cascade = "save-update"/>
</class>
</hibernate-mapping>
Donc, si nous créons une nouvelle commande et qu'un nouveau client y est associé et que nous disons, enregistrez cette commande, nous pourrions vouloir la mettre en cascade. Mais une chose que nous ne voudrions probablement pas faire est si une commande est supprimée pour supprimer le client correspondant.
Donc, ici, nous voudrions faire une mise à jour de sauvegarde, donc en utilisant une mise à jour de sauvegarde, elle mettra en cascade toutes les sauvegardes ou mises à jour à ce client. Donc, si nous avons un nouveau client ou si nous changeons de client, cela se répercutera en cascade. S'il s'agit d'une suppression, cela ne le supprimera pas de la base de données.
Donc, en exécutant à nouveau notre application, tout fonctionne toujours comme prévu.
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
The orders were ordered by:
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
John Doe (10b2a3d7-7fcf-483c-b1da-a5bb00b8512e)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: e6680e30-5b3b-4efa-b017-a5bb00b85133
Order Id: b03858e7-8c36-4555-8878-a5bb00b85134
Press <ENTER> to exit...
Maintenant, vous devriez jeter un œil à votre application, rappelez-vous que la valeur par défaut est None et que vous devez penser à vos entités et à vos relations entre elles pour déterminer les cascades appropriées pour chacune de vos entités ainsi que chacune de vos relations dans cette base de données.
Dans ce chapitre, nous allons couvrir la fonction de chargement différé. C'est un concept entièrement différent par défaut et NHibernate n'a pas de chargement différé, par exemple si vous chargez un client, il ne chargera pas toutes les commandes.
La collection de commande sera chargée sur demande.
Toute association, que ce soit plusieurs-à-un ou une collection est chargée par défaut par défaut, elle nécessite un Open ISession.
Si vous avez fermé votre session ou si vous avez validé votre transaction, vous pouvez obtenir une exception de chargement différé qui ne peut pas extraire ces objets supplémentaires.
Vous devez faire attention au chargement paresseux et à la quantité de données dont vous avez réellement besoin.
Vous pouvez désactiver le chargement différé pour une association entière ou vous pouvez mettre lazy equals false ou vous pouvez également spécifier une stratégie de récupération.
Voici la Program.cs implémentation de fichier.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
Guid id;
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
id = newCustomer.Id;
tx.Commit();
}
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var reloaded = session.Load<Customer>(id);
Console.WriteLine("Reloaded:");
Console.WriteLine(reloaded);
Console.WriteLine("The orders were ordered by: ");
foreach (var order in reloaded.Orders) {
Console.WriteLine(order.Customer);
}
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Customer CreateCustomer() {
var customer = new Customer {
FirstName = "John",
LastName = "Doe",
Points =100,
HasGoldStatus = true,
MemberSince = new DateTime(2012, 1, 1),
CreditRating = CustomerCreditRating.Good,
AverageRating = 42.42424242,
Address = CreateLocation()
};
var order1 = new Order { Ordered = DateTime.Now };
customer.AddOrder(order1);
var order2 = new Order {
Ordered = DateTime.Now.AddDays(-1),
Shipped = DateTime.Now,
ShipTo = CreateLocation()
};
customer.AddOrder(order2); return customer;
}
private static Location CreateLocation() {
return new Location {
Street = "123 Somewhere Avenue",
City = "Nowhere",
Province = "Alberta",
Country = "Canada"
};
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect<();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
Pour comprendre cela, exécutons l'application et jetons un œil au NHibernate Profiler.
Comme vous pouvez le voir, nous avons la sélection du client, compte tenu d'un identifiant client particulier, puis nous avons également une autre table de sélection des commandes, lorsqu'elle accède réellement à la collection de ce client.
Nous avons donc 2 allers-retours vers la base de données. Maintenant, parfois, nous voudrions optimiser cela. Pour ce faire, passons à lacustomer.hbm.xml fichier et ajoutez une stratégie de récupération et demandez-lui de faire une récupération de jointure.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`" cascade = "all-delete-orphan"
fetch = "join">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
Comme vous pouvez voir que nous n'avons changé aucun code dans notre application, nous venons d'ajouter une stratégie de récupération dans le customer.hbm.xml. Exécutons à nouveau cette application, elle se comporte toujours exactement de la même manière. Regardons NHibernate Profiler.
Avant, le programme avait deux allers-retours vers la base de données, maintenant, il n'en a qu'un et c'est parce qu'il fait une jointure externe gauche ici.
Nous pouvons voir qu'il effectue une jointure externe gauche entre la table client et la table de commande en fonction de l'ID client, et par conséquent, il est capable de charger toutes ces informations à la fois.
Nous avons enregistré 1 aller-retour dans la base de données.
L'inconvénient est que les informations client seront dupliquées sur les deux lignes et c'est ainsi que fonctionne une jointure externe gauche SQL.
Donc, avec la stratégie de récupération, nous retirons un peu plus de données et nous économisons un aller-retour.
Vous pouvez également le faire au niveau de la requête, alors passons à la Program.cs et regardez l'exemple rechargé plus simple.
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
//var query = from customer in session.Query<Customer>()
// select customer;
//var reloaded = query.Fetch(x => x.Orders).ToList();
var reloaded = session.Load<Customer>(id);
Console.WriteLine("Reloaded:");
Console.WriteLine(reloaded);
Console.WriteLine("The orders were ordered by: ");
foreach (var order in reloaded.Orders) {
Console.WriteLine(order.Customer);
}
tx.Commit();
}
Ici, nous faisons une charge par le client. Maintenant, changeons-le en requête et nous utiliserons une requête de lien comme indiqué dans le code suivant.
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var query = from customer in session.Query<Customer>()
where customer.Id == id select customer;
var reloaded = query.Fetch(x => x.Orders).ToList().First();
Console.WriteLine("Reloaded:");
Console.WriteLine(reloaded);
tx.Commit();
}
Supprimons également la stratégie de récupération de la customer.hbm.xml fichier.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`" cascade = "all-delete-orphan">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
Exécutons à nouveau cette application et vous verrez la sortie suivante.
New Customer:
John Doe (00000000-0000-0000-0000-000000000000)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Unspecified)
CreditRating: Good
AverageRating: 42.42424242
Orders:
Order Id: 00000000-0000-0000-0000-000000000000
Order Id: 00000000-0000-0000-0000-000000000000
Reloaded:
John Doe (6ebacd17-f9ba-4ad8-9817-a5bb01112a5a)
Points: 100
HasGoldStatus: True
MemberSince: 1/1/2012 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 42.4242
Orders:
Order Id: 16a6596b-d56e-41c7-9681-a5bb01112a60
Order Id: d41d615b-0f21-4032-81db-a5bb01112a61
Press <ENTER> to exit...
Regardons maintenant le NHibernate Profiler, vous pouvez voir que nous avons à nouveau cette recherche de jointure impatiente, mais cette fois, elle est basée sur la requête.
Dans ce chapitre, nous couvrirons une autre fonctionnalité qui est les relations inverses. C'est une option amusante que vous verrez sur une collection qui est inversement égale à true et qui déroute également beaucoup de développeurs. Parlons donc de cette option. Pour comprendre cela, il faut vraiment penser au modèle relationnel. Supposons que vous ayez des associations bidirectionnelles utilisant une seule clé étrangère.
D'un point de vue relationnel, vous disposez d'une clé étrangère, qui représente à la fois le client à commander et les commandes au client.
À partir du modèle OO, vous avez des associations unidirectionnelles utilisant ces références.
Rien n'indique que deux associations unidirectionnelles représentent la même association bidirectionnelle dans la base de données.
Le problème ici est que NHibernate n'a pas assez d'informations pour savoir que customer.orders et order.customer représentent la même relation dans la base de données.
Nous devons fournir inverse equals true à titre indicatif, c'est parce que les associations unidirectionnelles utilisent les mêmes données.
Si nous essayons de sauvegarder ces relations qui ont 2 références, NHibernate essaiera de mettre à jour cette référence deux fois.
Il effectuera en fait un aller-retour supplémentaire vers la base de données, et il aura également 2 mises à jour de cette clé étrangère.
L'inverse est égal à vrai indique à NHibernate quel côté de la relation ignorer.
Lorsque vous l'appliquez du côté collection et NHibernate mettra toujours à jour la clé étrangère de l'autre côté, du côté objet enfant.
Ensuite, nous n'avons qu'une seule mise à jour de cette clé étrangère et nous n'avons pas de mises à jour supplémentaires pour ces données.
Cela nous permet d'éviter ces mises à jour en double de la clé étrangère et cela nous aide également à empêcher les violations de clé étrangère.
Jetons un coup d'œil à la customer.cs fichier dans lequel vous verrez le AddOrderet l'idée ici est que nous avons maintenant ce pointeur de retour de la commande au client et qu'il doit être défini. Ainsi, lorsqu'une commande est ajoutée à un client, le pointeur arrière de ce client est défini, sinon il serait nul, nous en avons donc besoin pour que cela reste correctement connecté dans le graphique d'objets.
using System;
using System.Text;
using Iesi.Collections.Generic;
namespace NHibernateDemo {
public class Customer {
public Customer() {
MemberSince = DateTime.UtcNow; Orders = new HashedSet<Order>();
}
public virtual Guid Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual double AverageRating { get; set; }
public virtual int Points { get; set; }
public virtual bool HasGoldStatus { get; set; }
public virtual DateTime MemberSince { get; set; }
public virtual CustomerCreditRating CreditRating { get; set; }
public virtual Location Address { get; set; }
public virtual ISet<Order> Orders { get; set; }
public virtual void AddOrder(Order order) { Orders.Add(order); order.Customer = this; }
public override string ToString() {
var result = new StringBuilder();
result.AppendFormat("{1} {2} ({0})\r\n\tPoints: {3}\r\n\tHasGoldStatus:
{4}\r\n\tMemberSince: {5} ({7})\r\n\tCreditRating: {6}\r\n\tAverageRating:
{8}\r\n", Id, FirstName, LastName, Points, HasGoldStatus, MemberSince,
CreditRating, MemberSince.Kind, AverageRating);
result.AppendLine("\tOrders:");
foreach(var order in Orders) {
result.AppendLine("\t\t" + order);
}
return result.ToString();
}
}
public class Location {
public virtual string Street { get; set; }
public virtual string City { get; set; }
public virtual string Province { get; set; }
public virtual string Country { get; set; }
}
public enum CustomerCreditRating {
Excellent,
VeryVeryGood,
VeryGood,
Good,
Neutral,
Poor,
Terrible
}
}
Voici la Program.cs implémentation de fichier.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
Guid id;
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var newCustomer = CreateCustomer();
Console.WriteLine("New Customer:");
Console.WriteLine(newCustomer);
session.Save(newCustomer);
id = newCustomer.Id;
tx.Commit();
}
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var query = from customer in session.Query<Customer>() where
customer.Id == id select customer;
var reloaded = query.Fetch(x => x.Orders).ToList().First();
Console.WriteLine("Reloaded:"); Console.WriteLine(reloaded);
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Customer CreateCustomer() {
var customer = new Customer {
FirstName = "John",
LastName = "Doe",
Points = 100,
HasGoldStatus = true,
MemberSince = new DateTime(2012, 1, 1),
CreditRating = CustomerCreditRating.Good,
AverageRating = 42.42424242,
Address = CreateLocation()
};
var order1 = new Order { Ordered = DateTime.Now };
customer.AddOrder(order1); var order2 = new Order {
Ordered = DateTime.Now.AddDays(-1),
Shipped = DateTime.Now,
ShipTo = CreateLocation()
};
customer.AddOrder(order2);
return customer;
}
private static Location CreateLocation() {
return new Location {
Street = "123 Somewhere Avenue",
City = "Nowhere",
Province = "Alberta",
Country = "Canada"
};
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
Il va l'enregistrer dans la base de données, puis la recharger. Maintenant, exécutons votre application et ouvrons le NHibernate Profiler et voyons comment il l'a réellement enregistré.
Vous remarquerez que nous avons 3 groupes de déclarations. Le premier insérera le client, et l'ID de ce client est le Guid, qui est mis en surbrillance. La deuxième instruction est insérée dans la table des commandes.
Vous remarquerez que le même Guid ID client est défini là-dedans, alors ayez cette clé étrangère définie. La dernière instruction est la mise à jour, qui mettra à nouveau à jour la clé étrangère avec le même identifiant client.
Maintenant, le problème est que le client a les commandes, et les commandes ont le client, il n'y a aucun moyen que nous n'ayons pas dit à NHibernate que c'est en fait la même relation. La façon dont nous faisons cela est avec inverse égal à vrai.
Alors allons à notre customer.hbm.xml mappage et définissez l'inverse sur true comme indiqué dans le code suivant.
<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns = "urn:nhibernate-mapping-2.2" assembly = "NHibernateDemo"
namespace = "NHibernateDemo">
<class name = "Customer">
<id name = "Id">
<generator class = "guid.comb"/>
</id>
<property name = "FirstName"/>
<property name = "LastName"/>
<property name = "AverageRating"/>
<property name = "Points"/>
<property name = "HasGoldStatus"/>
<property name = "MemberSince" type = "UtcDateTime"/>
<property name = "CreditRating" type = "CustomerCreditRatingType"/>
<component name = "Address">
<property name = "Street"/>
<property name = "City"/>
<property name = "Province"/>
<property name = "Country"/>
</component>
<set name = "Orders" table = "`Order`" cascade = "all-delete-orphan"
inverse = "true">
<key column = "CustomerId"/>
<one-to-many class = "Order"/>
</set>
</class>
</hibernate-mapping>
Lors de l'enregistrement des commandes, il définira cette clé étrangère du côté de la commande. Maintenant, exécutons à nouveau cette application et ouvrons le profileur NHibernate.
Si nous regardons comment ceux-ci sont insérés, nous obtenons l'insertion dans le client et l'insertion dans les commandes, mais nous n'avons pas cette mise à jour en double de la clé étrangère car elle est mise à jour lorsque les commandes sont enregistrées.
Maintenant, vous devez noter que si vous n'avez qu'une association unidirectionnelle et que c'est l'ensemble qui maintient cette relation, alors si vous activez l'inverse est égal à vrai, cette clé étrangère ne sera jamais définie et ces éléments n'auront jamais leur clés étrangères définies dans la base de données.
Si vous regardez la relation plusieurs à un dans le Order.hbm.xml fichier et que vous recherchez l'inverse, il n'a en fait pas d'attribut inverse.
Il est toujours défini à partir de l'élément enfant, mais si vous avez une collection plusieurs-à-plusieurs, vous pouvez la définir de chaque côté.
Dans ce chapitre, nous expliquerons le fonctionnement des fonctionnalités Load et Get et comment nous pouvons les utiliser. Ce sont deux API très similaires fournies parISession pour charger un objet par clé primaire.
Get - il renverra l'objet ou un nul.
Load - il retournera l'objet ou il lancera un ObjectNotFoundException.
Maintenant, pourquoi avons-nous ces deux API différentes?
Charge
C'est parce que Load peut optimiser les aller-retour de la base de données beaucoup plus efficacement.
Load renvoie en fait un objet proxy et n'a pas besoin d'accéder à la base de données lorsque vous émettez cet appel Load.
Lorsque vous accédez à ce proxy, l'objet ne se trouve pas dans la base de données, il peut lancer une exception ObjectNotFoundException à ce stade.
Avoir
Inversement, avec Get en raison des limitations du CLR ou Common Language Runtime et NHibernate doit aller dans la base de données immédiatement, vérifier si les objets sont là et retourner null, s'il n'est pas présent.
Il n'a pas l'option d'objet de retarder cette extraction, cet aller-retour vers la base de données à une date ultérieure, car il ne peut pas renvoyer un objet proxy et qui a échangé cet objet proxy contre un null, lorsque l'utilisateur y accède réellement.
Jetons un coup d'œil à un exemple simple dans lequel vous verrez comment ils sont réellement utilisés et la différence entre Get et Load. Nous continuerons avec les mêmes classes de domaineCustomers et Orders et de même les mêmes fichiers de mappage du dernier chapitre.
Dans cet exemple, nous utiliserons d'abord Get comme indiqué dans le programme suivant.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var id1 = Guid.Parse("4e97c816-6bce-11e1-b095-6cf049ee52be");
var id2 = Guid.Parse("AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE");
var customer1 = session.Get<Customer>(id1);
Console.WriteLine("Customer1 data");
Console.WriteLine(customer1);
var customer2 = session.Get<Customer>(id2);
Console.WriteLine("Customer2 data");
Console.WriteLine(customer2);
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
Comme vous pouvez le voir, nous avons deux GuidID, le premier est un bon ID, c'est l'ID d'un client dont nous savons qu'il se trouve dans la base de données. Alors que le deuxième ID n'est pas présent dans la base de données. Ces deux identifiants sont passés en paramètre àGet() méthode, puis le résultat est imprimé sur la console.
Lorsque le code ci-dessus est compilé et exécuté, vous verrez la sortie suivante.
Customer1 data
Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
Points: 74
HasGoldStatus: True
MemberSince: 4/4/2009 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
Customer2 data
Press <ENTER> to exit...
Comme vous pouvez le voir, les données Client1 sont imprimées mais les données Client2 sont vides, c'est parce que l'enregistrement Client2 n'est pas disponible dans la base de données.
Lorsque vous exécutez à nouveau votre application, nous pouvons insérer un point d'arrêt avant l'instruction de validation, puis examinons les deux clients dans la fenêtre Espion.
Comme vous pouvez le voir, les données Customer1 sont disponibles, tandis que Customer2 est nul et le type est NHibernateDemo.Customer pour les deux.
Utilisons maintenant la méthode Load au lieu de Get dans le même exemple que celui indiqué dans le code suivant.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var id1 = Guid.Parse("4e97c816-6bce-11e1-b095-6cf049ee52be");
var id2 = Guid.Parse("AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE");
var customer1 = session.Load<Customer>(id1);
Console.WriteLine("Customer1 data");
Console.WriteLine(customer1);
var customer2 = session.Load<Customer>(id2);
Console.WriteLine("Customer2 data");
Console.WriteLine(customer2);
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
Maintenant, exécutons cet exemple et vous verrez que l'exception suivante est lancée comme indiqué dans la capture d'écran.
Maintenant, si vous regardez la fenêtre de surveillance, vous verrez que le type est proxy client pour les deux objets. Et vous voyez également les mêmes données pour Customer1 sur la fenêtre de la console.
Customer1 data
Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
Points: 74
HasGoldStatus: True
MemberSince: 4/4/2009 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
Customer2 data
Dans ce chapitre, nous couvrirons une autre API courante que les gens utiliseront est le fournisseur NHibernate LINQ. Son accès via une méthode d'extension sur ISession et la signature est unQuery <T>. Il existe deux types de syntaxe lors de l'utilisation de LINQ -
- Syntaxe de chaînage de requêtes
- Syntaxe de la compréhension des requêtes
Syntaxe de chaînage de requêtes
Vous pouvez accéder à n'importe quel enregistrement de la base de données en utilisant la syntaxe de la chaîne de méthodes comme indiqué dans le programme suivant.
var customer = session.Query<Customer>() .Where(c => c.FirstName == "Laverne")
Vous pouvez voir que nous avons une requête, ainsi qu'une clause WHERE, vous pouvez avoir des clauses WHERE supplémentaires et une clause select de même.
Il s'agit d'une syntaxe de chaîne de méthodes standard que vous pouvez utiliser dans LINQ normal.
LINQ to Objects ou LINQ to SQL, tout autre fournisseur LINQ que vous connaissez peut-être.
Jetons un œil à un exemple simple dans lequel nous récupérerons le client dont le prénom est Laverne. Il est maintenant possible que nous ayons plus d'un client dont le prénom est Laverne, nous ne récupérerons donc que le premier.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var customer = session.Query<Customer>()
.Where(c => c.FirstName == "Laverne").First();
Console.WriteLine(customer);
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
Maintenant, lorsque le code ci-dessus est compilé et exécuté, vous verrez la sortie suivante.
Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
Points: 74
HasGoldStatus: True
MemberSince: 4/4/2009 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
Press <ENTER> to exit...
Syntaxe de la compréhension des requêtes
Il y a aussi la syntaxe de compréhension des requêtes, qui ressemble beaucoup plus à SQL en utilisant les mots-clés from, where et select.
Examinons donc le même exemple, mais cette fois, nous utilisons la syntaxe de compréhension LINQ, qui ressemble beaucoup plus à SQL, comme indiqué dans le programme suivant.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var customer = (from c in session.Query<Customer>()
where c.FirstName == "Laverne" select c).First();
Console.WriteLine(customer);
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
Maintenant, exécutons à nouveau cette application et vous verrez la sortie suivante.
Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
Points: 74
HasGoldStatus: True
MemberSince: 4/4/2009 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
Press <ENTER> to exit...
Jetons un coup d'œil à un autre exemple dans lequel nous récupérerons tous ces clients, dont le prénom commence par la lettre H.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var customers = session.Query<Customer>() .Where(c =<
c.FirstName.StartsWith("H"));
foreach (var customer in customers.ToList()) {
Console.WriteLine(customer);
}
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
De même, la syntaxe de compréhension des requêtes ressemblera au programme suivant.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var customers = from c in session.Query<Customer>()
where c.FirstName.StartsWith("H") select c;
foreach (var customer in customers.ToList()) {
Console.WriteLine(customer);
}
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
Exécutons à nouveau cette application et vous verrez tous les clients, dont le prénom commence par l'alphabet H.
Herman Crooks (4ead3480-6bce-11e1-b15c-6cf049ee52be)
Points: 74
HasGoldStatus: True
MemberSince: 12/3/2010 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ead3480-6bce-11e1-b15d-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b15e-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b15f-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b160-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b161-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b162-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b163-6cf049ee52be
Hudson Bins (4ec03f80-6bce-11e1-b2b7-6cf049ee52be)
Points: 56
HasGoldStatus: False
MemberSince: 10/20/2008 12:00:00 AM (Utc)
CreditRating: Terrible
AverageRating: 0
Orders:
Order Id: 4ec03f80-6bce-11e1-b2b8-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2b9-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2ba-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bb-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bc-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bd-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2be-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bf-6cf049ee52be
Hettie Feest (4ec50240-6bce-11e1-b300-6cf049ee52be)
Points: 82
HasGoldStatus: False
MemberSince: 4/10/2009 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ec50240-6bce-11e1-b301-6cf049ee52be
Order Id: 4ec50240-6bce-11e1-b302-6cf049ee52be
Order Id: 4ec50240-6bce-11e1-b303-6cf049ee52be
Press <ENTER> to exit...
Dans ce chapitre, nous couvrirons Hibernate Query Language. HQL est partagé à la fois par Java Hibernate et NHibernate.
C'est le mécanisme de requête le plus ancien avec Criteria.
Il a été implémenté très tôt et il s'agit d'une requête basée sur une chaîne API.
Vous y accédez via ISession CreateQuery, et il est presque similaire à SQL.
Il utilise plusieurs des mêmes mots-clés, mais a une syntaxe simplifiée.
C'est l'un des exemples les plus courants, si vous cherchez comment effectuer une requête, vous trouverez souvent des exemples HQL.
Ce qui suit est un exemple simple de HQL -
var customers = session.CreateQuery("select c from Customer c where c.FirstName = 'Laverne'");
Donc, ici, vous pouvez voir qu'ils sélectionnent C du client, cela ressemble beaucoup à SQL. Il s'agit d'une chaîne opaque en ce qui concerne NHibernate, donc vous ne savez pas si c'est un HQL valide jusqu'à l'exécution, ce qui est l'un des inconvénients.
L'une des forces du fournisseur LINQ est que vous pouvez obtenir la prise en charge du temps de compilation.
Mais HQL, est l'un des mécanismes de requête les plus flexibles souvent utilisés. On dit que s'il n'y a pas d'autre moyen de le faire, il y a un moyen de le faire en HQL.
Jetons un coup d'œil à un exemple simpe dans lequel nous recréerons nos requêtes LINQ en utilisant HQL à la place. Vous pouvez accéder à HQL en appelant lesession.CreateQuery et passer en paramètre à l'aide d'une chaîne HQL.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var customers = session.CreateQuery("select c from Customer c
where c.FirstName = 'Laverne'");
foreach (var customer in customers.List<Customer>()) {
Console.WriteLine(customer);
}
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
Cette chaîne HQL ressemble beaucoup à SQL, la principale différence est que FirstName est le nom de la propriété et non le nom de la colonne.
Donc, s'il y a une différence entre les deux, vous utilisez le nom de la propriété. Même chose, cela ressemble à un nom de table, mais c'est en fait le nom de la classe dans laquelle nous sélectionnons.
Si la table principale était nommée Clients, nous utiliserions toujours Customer dans notre requête HQL.
Exécutons cette application et vous verrez la sortie suivante.
Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
Points: 74
HasGoldStatus: True
MemberSince: 4/4/2009 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
Press <ENTER> to exit...
Jetons un coup d'œil à un autre exemple simple dans lequel nous récupérerons tous les clients dont le prénom commence par la lettre H en utilisant HQL.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var customers = session.CreateQuery("select c from Customer c
where c.FirstName like 'H%'");
foreach (var customer in customers.List<Customer>()) {
Console.WriteLine(customer);
}
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
Exécutons à nouveau votre application et vous verrez que tous les clients dont le nom commence par H sont renvoyés par cette requête.
Herman Crooks (4ead3480-6bce-11e1-b15c-6cf049ee52be)
Points: 74
HasGoldStatus: True
MemberSince: 12/3/2010 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ead3480-6bce-11e1-b15d-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b15e-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b15f-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b160-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b161-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b162-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b163-6cf049ee52be
Hudson Bins (4ec03f80-6bce-11e1-b2b7-6cf049ee52be)
Points: 56
HasGoldStatus: False
MemberSince: 10/20/2008 12:00:00 AM (Utc)
CreditRating: Terrible
AverageRating: 0
Orders:
Order Id: 4ec03f80-6bce-11e1-b2b8-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2b9-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2ba-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bb-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bc-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bd-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2be-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bf-6cf049ee52be
Hettie Feest (4ec50240-6bce-11e1-b300-6cf049ee52be)
Points: 82
HasGoldStatus: False
MemberSince: 4/10/2009 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ec50240-6bce-11e1-b301-6cf049ee52be
Order Id: 4ec50240-6bce-11e1-b302-6cf049ee52be
Order Id: 4ec50240-6bce-11e1-b303-6cf049ee52be
Press <ENTER> to exit...
Nous pouvons faire des choses plus compliquées comme vouloir toutes les commandes où les clients avec un nombre de commandes est supérieur à 9. Voici la requête HQL pour le même.
var customers = session.CreateQuery("select c from Customer c
where size(c.Orders) > 9");
foreach (var customer in customers.List<Customer>()) {
Console.WriteLine(customer);
}
Nous devons également indiquer que nous avons besoin d'une taille ici ou d'un nombre ou d'une longueur. En HQL, nous avons la possibilité d'utiliser la méthode de taille spéciale comme indiqué ci-dessus.
L'autre façon d'écrire ceci, si vous préférez, est c.Orders.size, et cela a l'effet exact.
var customers = session.CreateQuery("select c from Customer c
where c.Orders.size > 9");
foreach (var customer in customers.List<Customer>()) {
Console.WriteLine(customer);
}
Lançons cette application.
Lindsay Towne (4ea3aef6-6bce-11e1-b0cb-6cf049ee52be)
Points: 50
HasGoldStatus: False
MemberSince: 4/13/2007 12:00:00 AM (Utc)
CreditRating: VeryGood
AverageRating: 0
Orders:
Order Id: 4ea3aef6-6bce-11e1-b0cc-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0cd-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0ce-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0cf-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0d0-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0d1-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0d2-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0d3-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0d4-6cf049ee52be
Order Id: 4ea3aef6-6bce-11e1-b0d5-6cf049ee52be
Wyman Hammes (4ea61056-6bce-11e1-b0e2-6cf049ee52be)
Points: 32
HasGoldStatus: False
MemberSince: 2/5/2011 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 0
Orders:
Order Id: 4ea61056-6bce-11e1-b0e3-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0e4-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0e5-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0e6-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0e7-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0e8-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0e9-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0ea-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0eb-6cf049ee52be
Order Id: 4ea61056-6bce-11e1-b0ec-6cf049ee52be
Press <ENTER> to exit...
Vous pouvez voir que tous les clients, qui ont plus de 9 commandes sont récupérés de la base de données.
Dans ce chapitre, nous couvrirons le mécanisme de requêtes de critères. leNHibernate Query by Criteria API vous permet de créer une requête en manipulant des objets critères lors de l'exécution.
Cette approche vous permet de spécifier des contraintes de manière dynamique sans manipulations directes de chaînes, mais elle ne perd pas beaucoup de la flexibilité ou de la puissance de HQL.
En revanche, les requêtes exprimées sous forme de critères sont souvent moins lisibles que les requêtes exprimées en HQL.
La syntaxe des critères classiques est une API de requête basée sur des objets, comme illustré dans le programme suivant.
var customers = session.CreateCriteria<Customer>().Add(Restrictions.Like("FirstName", "H%"));
Comme vous pouvez le voir, nous faisons une session de création de critères sur le client, et maintenant nous ajoutons un objet de restriction à cette requête.
Ceci est utile pour les pages de requête où les utilisateurs peuvent sélectionner certaines options, mais pas d'autres.
Il est plus facile de créer la requête sous la forme d'une sorte d'arborescence semblable à une structure de requête plutôt qu'en HQL ou LINQ, où vous pouvez utiliser la clause AND ou OR dans WHERE.
Il est plus facile d'ajouter simplement des restrictions supplémentaires à l'aide de ces objets critères.
Jetons un coup d'œil à un exemple simple dans lequel nous allons créer une requête et accéder à l'API des critères via createCriteria puis ajoutez une restriction selon laquelle le prénom commence par H.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var customers = session.CreateCriteria<Customer>()
.Add(Restrictions.Like("FirstName", "H%"));
foreach (var customer in customers.List<Customer>()) {
Console.WriteLine(customer);
}
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
Lorsque le code ci-dessus est compilé et exécuté, vous verrez la sortie suivante.
Herman Crooks (4ead3480-6bce-11e1-b15c-6cf049ee52be)
Points: 74
HasGoldStatus: True
MemberSince: 12/3/2010 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ead3480-6bce-11e1-b15d-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b15e-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b15f-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b160-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b161-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b162-6cf049ee52be
Order Id: 4ead3480-6bce-11e1-b163-6cf049ee52be
Hudson Bins (4ec03f80-6bce-11e1-b2b7-6cf049ee52be)
Points: 56
HasGoldStatus: False
MemberSince: 10/20/2008 12:00:00 AM (Utc)
CreditRating: Terrible
AverageRating: 0
Orders:
Order Id: 4ec03f80-6bce-11e1-b2b8-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2b9-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2ba-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bb-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bc-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bd-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2be-6cf049ee52be
Order Id: 4ec03f80-6bce-11e1-b2bf-6cf049ee52be
Hettie Feest (4ec50240-6bce-11e1-b300-6cf049ee52be)
Points: 82
HasGoldStatus: False
MemberSince: 4/10/2009 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ec50240-6bce-11e1-b301-6cf049ee52be
Order Id: 4ec50240-6bce-11e1-b302-6cf049ee52be
Order Id: 4ec50240-6bce-11e1-b303-6cf049ee52be
Press <ENTER> to exit…
Jetons un œil à un autre exemple simple dans lequel nous récupérerons le client dont le prénom est égal à "Laverne"
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var customers = session.CreateCriteria<Customer>()
.Add(Restrictions.Eq("FirstName", "Laverne")) .List<Customer>();
foreach (var customer in customers) {
Console.WriteLine(customer);
}
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
Exécutons à nouveau cette application et vous verrez la sortie suivante.
Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
Points: 74
HasGoldStatus: True
MemberSince: 4/4/2009 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
Press <ENTER> to exit...
Désormais, l'un des inconvénients majeurs de l'API de critères réside dans ces chaînes opaques dans les noms de propriétés. Ainsi, si le prénom était refactorisé pour être autre chose, l'outil de refactoring ne capturerait pas nécessairement la chaîne opaque.
Dans ce chapitre, nous couvrirons les requêtes QueryOver. Il s'agit d'une nouvelle syntaxe qui ressemble plus à LINQ en utilisant la syntaxe de la chaîne de méthodes comme indiqué dans la requête suivante.
var customers = session.QueryOver<Customer>() .Where(x => x.FirstName == "Laverne");
C'est encore des critères sous les couvertures, mais maintenant nos requêtes sont fortement typées.
Comme nous l'avons vu dans la requête de critères, le prénom est juste une chaîne opaque, maintenant nous utilisons en fait un x.FirstName, de sorte que le prénom est remanié et renommé qui est modifié dans la requête de critères de style de lien à l'aide de la requête over.
Nous pouvons encore faire beaucoup de choses similaires, mais vous ne pouvez pas utiliser la syntaxe de compréhension de requête avec query over, vous devez utiliser la syntaxe de la chaîne de méthodes et vous ne pouvez pas mélanger et faire correspondre le lien et les critères.
Pour de nombreuses requêtes, la requête via l'API est très utile et fournit une syntaxe d'objet beaucoup plus facile à comprendre que l'utilisation directe de critères.
Jetons un coup d'œil à un exemple simple dans lequel nous récupérerons un client dont le prénom est Laverne à l'aide d'une requête over.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
var customers = session.QueryOver<Customer>()
.Where(x => x.FirstName == "Laverne");
foreach (var customer in customers.List()) {
Console.WriteLine(customer);
}
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
Comme vous pouvez le voir, il s'agit toujours de critères sous les couvertures, mais c'est juste une syntaxe plus agréable.
Lorsque le code ci-dessus est compilé et exécuté, vous verrez la sortie suivante.
Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
Points: 74
HasGoldStatus: True
MemberSince: 4/4/2009 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
Press <ENTER> to exit...
L'un des inconvénients est que, disons que nous voulons dire que FirstName.StartsWith(“A”) comme indiqué dans le programme suivant.
var customers = session.QueryOver<Customer>() .Where(x => x.FirstName.StartsWith("A"));
foreach (var customer in customers.List()) {
Console.WriteLine(customer);
}
tx.Commit();
Maintenant, exécutons à nouveau l'application et vous verrez que ce n'est pas un fournisseur LINQ car il ne sait pas ce que cela StartsWith méthode est, donc vous obtiendrez un RunTime exception.
L'exception indique un appel de méthode non reconnu. Ici, nous faisons la chose évidente, mais cela ne fonctionne pas nécessairement.
Essayons autre chose, comme FirstName est égal à «A%» comme indiqué dans le code suivant.
var customers = session.QueryOver<Customer>() .Where(x => x.FirstName == "A%");
foreach (var customer in customers.List()) {
Console.WriteLine(customer);
}
Exécutons à nouveau ceci et vous verrez que nous n'obtiendrons aucun résultat comme indiqué ci-dessous.
Press <ENTER> to exit...
Pour comprendre pourquoi nous n'obtenons aucun résultat, jetons un œil au profileur NHibernate.
Comme vous pouvez le voir, le prénom est égal à A% qui ne l'est pas. Un% est utilisé en SQL avec l'opérateur like. Nous devons maintenant créer une restriction dans la clause WHERE comme indiqué dans le programme suivant.
var customers = session.QueryOver<Customer>()
.Where(Restrictions.On<Customer>(c => c.FirstName).IsLike("A%"));
foreach (var customer in customers.List()) {
Console.WriteLine(customer);
}
Exécutons à nouveau votre application et vous verrez que tous les clients sont récupérés avec le prénom commençant par A.
Alejandrin Will (4ea3aef6-6bce-11e1-b0b4-6cf049ee52be)
Points: 24
HasGoldStatus: False
MemberSince: 10/1/2011 12:00:00 AM (Utc)
CreditRating: VeryVeryGood
AverageRating: 0
Orders:
Order Id: 4ea3aef6-6bce-11e1-b0b5-6cf049ee52be
Austyn Nolan (4ea871b6-6bce-11e1-b110-6cf049ee52be)
Points: 67
HasGoldStatus: True
MemberSince: 12/29/2007 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ea871b6-6bce-11e1-b111-6cf049ee52be
Antonia Murphy (4ea871b6-6bce-11e1-b121-6cf049ee52be)
Points: 72
HasGoldStatus: True
MemberSince: 6/15/2009 12:00:00 AM (Utc)
CreditRating: Terrible
AverageRating: 0
Orders:
Order Id: 4ea871b6-6bce-11e1-b122-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b123-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b124-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b125-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b126-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b127-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b128-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b129-6cf049ee52be
Order Id: 4ea871b6-6bce-11e1-b12a-6cf049ee52be
Cela fonctionne de la même manière qu'avant, sauf en utilisant ce nouveau QueryOversyntaxe. De nombreux développeurs trouvent que la syntaxe LINQ est plus accessible et fait souvent les bonnes choses.
Si LINQ ne peut pas le gérer, alors vous commencerez à regarder HQL ou Criteria pour voir si cela sera plus approprié.
Il vous donne juste une syntaxe différente, donc Criteria, les critères de création et QueryOver vous fournissent juste un autre mécanisme d'interrogation qui vous permet d'extraire des données de la base de données en utilisant NHibernate.
Dans ce chapitre, nous expliquerons comment utiliser les requêtes SQL natives dans NHibernate. Si vous utilisez le SQL manuscrit depuis un certain nombre d'années, vous craignez peut-être que l'ORM vous enlève une partie de l'expressivité et de la flexibilité auxquelles vous êtes habitué.
Les puissantes fonctionnalités de requête de NHibernate vous permettent de faire presque tout ce que vous feriez en SQL, et dans certains cas plus.
Pour les rares cas où vous ne pouvez pas faire en sorte que les propres fonctions de requête de NHibernate fassent exactement ce que vous voulez.
NHibernate vous permet de récupérer des objets en utilisant le dialecte SQL natif de votre base de données.
Jetons un coup d'œil à un exemple simple des requêtes Native SQL dans NHibernate.
using System;
using System.Data;
using System.Linq;
using System.Reflection;
using HibernatingRhinos.Profiler.Appender.NHibernate;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.Driver;
using NHibernate.Linq;
using NHibernate;
namespace NHibernateDemo {
internal class Program {
private static void Main() {
var cfg = ConfigureNHibernate();
var sessionFactory = cfg.BuildSessionFactory();
using(var session = sessionFactory.OpenSession())
using(var tx = session.BeginTransaction()) {
IQuery sqlQuery = session.CreateSQLQuery("SELECT * FROM
CUSTOMER").AddEntity(typeof(Customer));
var customers = sqlQuery.List<Customer>();
foreach (var customer in customers) {
Console.WriteLine(customer);
}
tx.Commit();
}
Console.WriteLine("Press <ENTER> to exit...");
Console.ReadLine();
}
private static Configuration ConfigureNHibernate() {
NHibernateProfiler.Initialize();
var cfg = new Configuration();
cfg.DataBaseIntegration(x => {
x.ConnectionStringName = "default";
x.Driver<SqlClientDriver>();
x.Dialect<MsSql2008Dialect>();
x.IsolationLevel = IsolationLevel.RepeatableRead;
x.Timeout = 10;
x.BatchSize = 10;
});
cfg.SessionFactory().GenerateStatistics();
cfg.AddAssembly(Assembly.GetExecutingAssembly());
return cfg;
}
}
}
L'exemple ci-dessus utilise CreateSQLQuery() pour récupérer une liste d'objets, et vous remarquerez également que le type d'entité racine que vous souhaitez que la requête renvoie est spécifié comme Client.
Lançons votre application et vous verrez que tous les clients sont récupérés de la base de données.
Emerson Prosacco (4ec2a0e0-6bce-11e1-b2cf-6cf049ee52be)
Points: 17
HasGoldStatus: False
MemberSince: 6/22/2007 12:00:00 AM (Utc)
CreditRating: Excellent
AverageRating: 0
Orders:
Order Id: 4ec2a0e0-6bce-11e1-b2d0-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2d1-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2d2-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2d3-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2d4-6cf049ee52be
Kaci Friesen (4ec2a0e0-6bce-11e1-b2d5-6cf049ee52be)
Points: 30
HasGoldStatus: True
MemberSince: 5/25/2007 12:00:00 AM (Utc)
CreditRating: VeryVeryGood
AverageRating: 0
Orders:
Order Id: 4ec2a0e0-6bce-11e1-b2d6-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2d7-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2d8-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2d9-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2da-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2db-6cf049ee52be
Eveline Waters (4ec2a0e0-6bce-11e1-b2dc-6cf049ee52be)
Points: 58
HasGoldStatus: False
MemberSince: 10/29/2009 12:00:00 AM (Utc)
CreditRating: Good
AverageRating: 0
Orders:
Order Id: 4ec2a0e0-6bce-11e1-b2dd-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2de-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2df-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2e0-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2e2-6cf049ee52be
Molly Kuhn (4ec2a0e0-6bce-11e1-b2e3-6cf049ee52be)
Points: 73
HasGoldStatus: False
MemberSince: 12/16/2007 12:00:00 AM (Utc)
CreditRating: VeryGood
AverageRating: 0
Orders:
Order Id: 4ec2a0e0-6bce-11e1-b2e4-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2e5-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2e6-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2e7-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2e8-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2e9-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2ea-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2eb-6cf049ee52be
Order Id: 4ec2a0e0-6bce-11e1-b2ec-6cf049ee52be
Voici une autre façon d'écrire une requête SQL native comme indiqué ci-dessous.
IList<Customer> customers = session.CreateSQLQuery("SELECT * FROM CUSTOMER")
.AddScalar("Id", NHibernateUtil.Guid)
.AddScalar("FirstName", NHibernateUtil.String)
.AddScalar("LastName", NHibernateUtil.String) .List<Customer>();
Comme vous pouvez le voir, la requête ci-dessus spécifiait la chaîne de requête SQL et les colonnes et types à renvoyer.
Cela renverra une IList de tableaux d'objets avec des valeurs scalaires pour chaque colonne de la table Customer.
Seules ces trois colonnes seront renvoyées, même si la requête utilise * et peut renvoyer plus que les trois colonnes répertoriées.
Jetons un œil à un autre exemple simple.
IList<Customer> customers = session.CreateSQLQuery("SELECT * FROM CUSTOMER WHERE
FirstName = 'Laverne'")
.AddEntity(typeof(Customer)) .List<Customer>();
foreach (var customer in customers) {
Console.WriteLine(customer);
}
Exécutons à nouveau votre application et vous verrez la sortie suivante.
Laverne Hegmann (4e97c816-6bce-11e1-b095-6cf049ee52be)
Points: 74
HasGoldStatus: True
MemberSince: 4/4/2009 12:00:00 AM (Utc)
CreditRating: Neutral
AverageRating: 0
Orders:
Order Id: 4ea14d96-6bce-11e1-b095-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b096-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b097-6cf049ee52be
Order Id: 4ea14d96-6bce-11e1-b098-6cf049ee52be
Press <ENTER> to exit...
De même, vous pouvez spécifier n'importe quel type de requête SQL pour récupérer les données de la base de données.
Dans ce chapitre, nous couvrirons NHibernate couramment. Fluent NHibernate est une autre façon de mapper ou vous pouvez dire que c'est une alternative aux fichiers de mappage XML standard de NHibernate. Au lieu d'écrire du XML(.hbm.xml files)documents. Avec l'aide de Fluent NHibernate, vous pouvez écrire des mappages dans du code C # fortement typé.
Dans Fluent NHibernate, les mappages sont compilés avec le reste de votre application.
Vous pouvez facilement modifier vos mappages tout comme le code de votre application et le compilateur échouera sur toutes les fautes de frappe.
Il dispose d'un système de configuration conventionnel, dans lequel vous pouvez spécifier des modèles pour remplacer les conventions de dénomination et bien d'autres choses.
Vous pouvez également définir comment les choses doivent être nommées une fois, puis Fluent NHibernate s'occupe du reste.
Jetons un coup d'œil à un exemple simple en créant un nouveau projet de console. Dans ce chapitre, nous utiliserons une base de données simple dans laquelle nous avons une simple table Client comme le montre l'image suivante.
Installez Fluent NHibernate
La première étape consiste à démarrer Fluent NHibernate est d'installer le package Fluent NHibernate. Alors ouvrez leNuGet Package Manager Console et entrez la commande suivante.
PM> install-package FluentNHibernate
Une fois qu'il est installé avec succès, vous verrez le message suivant.
Ajoutons une classe de modèle simple de Customer et le programme suivant montre l'implémentation de la classe Customer.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FluentNHibernateDemo {
class Customer {
public virtual int Id { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
}
}
Maintenant, nous devons créer des mappages en utilisant NHibernate fluide, alors ajoutez une classe supplémentaire CustomerMapdans votre projet. Voici l'implémentation de la classe CustomerMap.
using FluentNHibernate.Mapping;
using System;
using System.Collections.Generic;
using System.Linq; using System.Text;
using System.Threading.Tasks;
namespace FluentNHibernateDemo {
class CustomerMap : ClassMap<Customer> {
public CustomerMap() {
Id(x => x.Id);
Map(x => x.FirstName);
Map(x => x.LastName);
Table("Customer");
}
}
}
Ajoutons une autre classe NHibernateHelper dans lequel nous définirons différents paramètres de configuration.
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate;
using NHibernate.Tool.hbm2ddl;
namespace FluentNHibernateDemo {
public class NHibernateHelper {
private static ISessionFactory _sessionFactory;
private static ISessionFactory SessionFactory {
get {
if (_sessionFactory == null)
InitializeSessionFactory(); return _sessionFactory;
}
}
private static void InitializeSessionFactory() {
_sessionFactory = Fluently.Configure()
String Data Source = asia13797\\sqlexpress;
String Initial Catalog = NHibernateDemoDB;
String Integrated Security = True;
String Connect Timeout = 15;
String Encrypt = False;
String TrustServerCertificate = False;
String ApplicationIntent = ReadWrite;
String MultiSubnetFailover = False;
.Database(MsSqlConfiguration.MsSql2008 .ConnectionString(
@"Data Source + Initial Catalog + Integrated Security + Connect Timeout
+ Encrypt + TrustServerCertificate + ApplicationIntent +
MultiSubnetFailover") .ShowSql() )
.Mappings(m => m.FluentMappings
.AddFromAssemblyOf<Program>())
.ExposeConfiguration(cfg => new SchemaExport(cfg)
.Create(true, true))
.BuildSessionFactory();
}
public static ISession OpenSession() {
return SessionFactory.OpenSession();
}
}
}
Passons maintenant au Program.cs fichier dans lequel nous allons démarrer une session, puis créer un nouveau client et enregistrer ce client dans la base de données comme indiqué ci-dessous.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FluentNHibernateDemo {
class Program {
static void Main(string[] args) {
using (var session = NHibernateHelper.OpenSession()) {
using (var transaction = session.BeginTransaction()) {
var customer = new Customer {
FirstName = "Allan",
LastName = "Bomer"
};
session.Save(customer);
transaction.Commit();
Console.WriteLine("Customer Created: " + customer.FirstName + "\t" +
customer.LastName);
}
Console.ReadKey();
}
}
}
}
Exécutons votre application et vous verrez la sortie suivante.
if exists (select * from dbo.sysobjects where id = object_id(N'Customer') and
OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table Customer
create table Customer (
Id INT IDENTITY NOT NULL,
FirstName NVARCHAR(255) null,
LastName NVARCHAR(255) null,
primary key (Id)
)
NHibernate: INSERT INTO Customer (FirstName, LastName) VALUES (@p0, @p1);
select SCOPE_IDENTITY();@p0 = 'Allan' [Type: String (4000)],
@p1 = 'Bomer' [Type: String (4000)]
Customer Created: Allan Bomer
Comme vous pouvez le voir, le nouveau client est créé. Pour voir l'enregistrement du client, allons à la base de données et voyons les données de vue et vous verrez qu'un client est ajouté.