La plupart des amis qui utilisent NHibernate pour le développement Web connaissent le mode Session-Per-Request, mais il n'y a pas beaucoup d'exemples sur la façon de l'utiliser correctement sur Internet. De nombreux articles sur Internet, y compris dans le jardin, ont commis la même erreur. et cette erreur s'est répandue...
Regardons d'abord un article de Flyear dans le jardin, "NHibernate One Session Per Request Simple Implementation".
Il n'y a rien de mal à configurer d'abord NHibernate :
<property name='current_session_context_class'>web</property>
L'erreur est dans la classe NHinbernateSessionFactory (les noms de classe sont tous faux). NHinbernateSessionFactory.GetCurrentSession ne devrait pas inclure d'opérations sur GetCurrentSession devrait en fait être très simple. Veuillez voir (le nom de la classe est changé en NHibernateHelper, court) :
classe publique scellée NHibernateHelper
{
public statique en lecture seule ISessionFactory SessionFactory ;
staticNHibernateHelper()
{
SessionFactory = nouvelle configuration()
.Configurer()
.AddAssembly(/**/)
.BuildSessionFactory();
}
ISession statique publique GetCurrentSession()
{
return SessionFactory.GetCurrentSession();
}
}
Configurez current_session_context_class en tant que web et NHibernate générera une instance de la classe NHibernate.Context.WebSessionContext lors de l'initialisation. Le code source de la classe WebSessionContext est le suivant :
[Sérialisable]
classe publique WebSessionContext : MapBasedSessionContext
{
//Champs
chaîne const privée SessionFactoryMapKey = "NHibernate.Context.WebSessionContext.SessionFactoryMapKey";
// Méthodes
public WebSessionContext (usine ISessionFactoryImplementor) : base (usine)
{ }
remplacement protégé IDictionary GetMap()
{
return (HttpContext.Current.Items[SessionFactoryMapKey] comme IDictionary);
}
remplacement protégé void SetMap (valeur IDictionary)
{
HttpContext.Current.Items[SessionFactoryMapKey] = valeur ;
}
}
WebSessionContext implémente le mode Session-Per-Request, qui encapsule HttpContext, nous n'avons donc pas besoin d'utiliser HttpContext dans notre classe auxiliaire (NHibernateSessionFactory ou NHibernateHelper).
Nous avons juste besoin d'obtenir la session à partir de l'instance de WebSessionContext. Obtenir l'ISession actuelle à partir de la classe WebSessionContext est assez simple, car WebSessionContext implémente l'interface ICurrentSessionContext :
interface publique ICurrentSessionContext
{
ISession SessionActuelle();
}
Classes et interfaces dans l'espace de noms NHibernate.Context
(Remarque : current_session_context_class peut également être configuré comme Managed_web, Call, thread_static, correspondant respectivement aux classes ManagedWebSessionContext, CallSessionContext et ThreadStaticSessionContext)
En utilisation réelle, nous n'avons pas besoin d'appeler directement la méthode CurrentSession() de WebSessionContext, car ISessionFactory fournit une méthode plus simple qui nous permet d'obtenir la Session en une seule étape :
interface publique ISessionFactory : IDisposable
{
ISession GetCurrentSession();
//......
}
Discutons de l'implémentation spécifique de la méthode ISessionFactory.GetCurrentSession :
La méthode Configuration.BuildSessionFactory renvoie en fait une instance de la classe SessionFactoryImpl. Jetons un bref coup d'œil à une partie du code de SessionFactoryImpl :
1 classe publique scellée SessionFactoryImpl
2 : ISessionFactoryImplementor, IMapping, ISessionFactory, IDisposable, IObjectReference
3 {
4 privé en lecture seule ICurrentSessionContext currentSessionContext ;
5
6 ISession publique GetCurrentSession()
7 {
8 si (this.currentSessionContext == null)
9 {
10 lancez une nouvelle HibernateException (
11 "Aucun CurrentSessionContext configuré (définissez la propriété current_session_context_class)!");
12}
13 renvoie this.currentSessionContext.CurrentSession();
14}
15
16 public ICurrentSessionContext CurrentSessionContext
17 {
18 obtenir { return this.currentSessionContext }
19}
20
21 ICurrentSessionContext privé BuildCurrentSessionContext()
vingt-deux {
23 nom de chaîne = PropertiesHelper.GetString("current_session_context_class", this.properties, null);
24 chaînes str2 = nom ;
25 si (str2 != nul)
26 {
27 if (str2 == "call") return new CallSessionContext(this);
28 if (str2 == "thread_static") renvoie un nouveau ThreadStaticSessionContext(this);
29 if (str2 == "web") renvoie un nouveau WebSessionContext(this);
30 if (str2 == "managed_web") renvoie un nouveau ManagedWebSessionContext(this);
31}
32 autres
33 renvoie nul ;
34 essayer
35 {
36 Tapez type = ReflectHelper.ClassForName(name);
37 retour (ICurrentSessionContext)Environment.BytecodeProvider.ObjectsFactory
38.CreateInstance(type, nouvel objet[] { this });
39 }
40 captures (exception exception)
41 {
42 log.Error("Impossible de construire le contexte de session actuel [" + nom + "]", exception);
43 renvoie null ;
44}
45 }
46 //......
47 }
Lorsque SessionFactoryImpl est instancié, il appelle la méthode BuildCurrentSessionContext() (ligne 21) pour attribuer une valeur au champ currentSessionContext. La valeur spécifique est déterminée par current_session_context_class dans le fichier de configuration.
GetCurrentSession() d'ISessionFactory appelle la méthode CurrentSession() (ligne 6) d'ICurrentSessionContext.
Le code ci-dessus est assez simple, tout le monde doit déjà le comprendre.
Il y a deux endroits inappropriés dans l'article « NHibernate One Session Per Request Simple Implementation » :
1. Toutes les requêtes ne nécessitent pas une session pour accéder à la base de données. Le code de Global.asax dans l'article exécute WebSessionContext.Bind() au début de toutes les requêtes, ce qui gaspillera beaucoup de session. Bien que la session de NHibernate soit légère, une approche plus raisonnable consiste à « vraiment besoin » de liaison temporelle.
2. Étant donné que la méthode WebSessionContext.Unbind nécessite une instance de l'interface ISessionFactory, nous sommes obligés d'utiliser notre classe d'assistance (NHibernateSessionFactory ou NHibernateHelper) pour exposer SessionFactory.
La première question est plus facile à résoudre, alors laissez-la dans la réponse pour communiquer avec tout le monde.
Je répondrai à la deuxième question dans le prochain essai.
Je n'apprends pas NHibernate depuis longtemps et je suis novice. S'il y a des erreurs, corrigez-moi !