NHibernate fil de sécurité à la session
J'ai été en utilisant NHibernate pour un certain temps maintenant et ont trouvé de temps à autre, que si j'essaie de demander à deux pages simultanément (ou aussi près que je peux) il sera parfois d'erreur. Donc, je suppose que c'était parce que ma gestion de Session n'était pas thread-safe.
Je pensais que c'était ma classe, j'ai donc essayé d'utiliser une méthode différente de ce blog http://pwigle.wordpress.com/2008/11/21/nhibernate-session-handling-in-aspnet-the-easy-way/ cependant, je reçois toujours les mêmes questions. L'erreur que j'obtiens est:
Server Error in '/AvvioCMS' Application.
failed to lazily initialize a collection, no session or session was closed
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: NHibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed
Ça ou pas datareader est ouvert, mais c'est le principal coupable.
J'ai placé ma session de la gestion de classe ci-dessous, quelqu'un peut tache pourquoi je suis peut-être avoir ces problèmes?
public interface IUnitOfWorkDataStore
{
object this[string key] { get; set; }
}
public static Configuration Init(IUnitOfWorkDataStore storage, Assembly[] assemblies)
{
if (storage == null)
throw new Exception("storage mechanism was null but must be provided");
Configuration cfg = ConfigureNHibernate(string.Empty);
foreach (Assembly assembly in assemblies)
{
cfg.AddMappingsFromAssembly(assembly);
}
SessionFactory = cfg.BuildSessionFactory();
ContextDataStore = storage;
return cfg;
}
public static ISessionFactory SessionFactory { get; set; }
public static ISession StoredSession
{
get
{
return (ISession)ContextDataStore[NHibernateSession.CDS_NHibernateSession];
}
set
{
ContextDataStore[NHibernateSession.CDS_NHibernateSession] = value;
}
}
public const string CDS_NHibernateSession = "NHibernateSession";
public const string CDS_IDbConnection = "IDbConnection";
public static IUnitOfWorkDataStore ContextDataStore { get; set; }
private static object locker = new object();
public static ISession Current
{
get
{
ISession session = StoredSession;
if (session == null)
{
lock (locker)
{
if (DBConnection != null)
session = SessionFactory.OpenSession(DBConnection);
else
session = SessionFactory.OpenSession();
StoredSession = session;
}
}
return session;
}
set
{
StoredSession = value;
}
}
public static IDbConnection DBConnection
{
get
{
return (IDbConnection)ContextDataStore[NHibernateSession.CDS_IDbConnection];
}
set
{
ContextDataStore[NHibernateSession.CDS_IDbConnection] = value;
}
}
}
Et le magasin réel que j'utilise est ceci:
public class HttpContextDataStore : IUnitOfWorkDataStore
{
public object this[string key]
{
get { return HttpContext.Current.Items[key]; }
set { HttpContext.Current.Items[key] = value; }
}
}
J'initialise la SessionFactory sur Application_Start avec:
NHibernateSession.Init(new HttpContextDataStore(), new Assembly[] {
typeof(MappedClass).Assembly});
Mise à jour
Salut les gars, merci pour vos conseils, j'ai essayé différentes choses pour essayer de simplifier le code, mais je suis toujours en cours d'exécution dans les mêmes problèmes et j'ai peut-être une idée de la raison.
J'ai créer la session, conformément à la demande lorsque cela est nécessaire, mais dans mon global.asax je suis l'élimination de la session sur Application_EndRequest. Cependant, je suis la recherche de la Application_EndRequest est déclenché plus d'une fois alors que je suis en debug à la fin de chargement d'une page. Je pensais que l'événement est supposer de feu une fois à la fin de la requête, mais si elle n'est pas et certains autres éléments sont d'essayer d'utiliser la Session (qui est ce que l'erreur est de se plaindre) pour quelque étrange raison qui pourrait être mon problème et que la Session est toujours "thread-safe" c'est juste d'être éliminés au début.
Quelqu'un a des idées? J'ai fait un google et vu que le VS serveur de développement est la cause des problèmes comme ça, mais je suis en cours d'exécution à travers IIS.
OriginalL'auteur John_ | 2009-03-10
Vous devez vous connecter pour publier un commentaire.
Alors que je n'ai pas vu l'intégralité de votre base de code ou le problème que vous essayez de résoudre, de repenser la façon dont vous utilisez NHibernate pourrait être dans l'ordre. À partir de la la documentation:
Que le dernier bit est la plus pertinente (et important dans le cas d'un environnement multithread) à ce que je dis. Un ISession doit être utilisé une fois pour une petite opération atomique et puis éliminés. Aussi à partir de la documentation:
La combinaison de ces deux idées, au lieu de stocker l'ISession lui-même, magasin de la fabrique de session puisque c'est le "gros" de l'objet. Vous pouvez alors employer quelque chose comme SessionManager.GetSession() comme un wrapper pour récupérer l'usine à partir de la session de stocker et d'instancier une session et de l'utiliser pour une opération.
Le problème est moins évident dans le contexte d'une ASP.NET application. Vous êtes statiquement portée de la ISession objet qui signifie qu'il est partagé dans le domaine d'application. Si deux demandes de Page sont créés au sein de ce domaine d'application de la durée de vie et sont exécutées simultanément, vous disposez maintenant de deux Pages (fils), le toucher de la même ISession qui est pas coffre-fort.
En gros, au lieu d'essayer de garder une session autour de pour aussi longtemps que possible, essayer de se débarrasser d'eux dès que possible et de voir si vous avez de meilleurs résultats.
EDIT:
Ok, je peux voir où vous tentez d'aller avec cela. Il semble que vous essayez de mettre en œuvre la Session Ouverte Dans la Vue modèle, et il ya un couple de différents itinéraires que vous pouvez prendre:
Si l'ajout d'un autre cadre n'est pas un problème, regardez quelque chose comme Spring.NET. Il est modulaire, de sorte que vous n'avez pas à utiliser l'ensemble de la chose, vous pouvez simplement utiliser le NHibernate module d'aide. Il prend en charge l'ouverture de session dans la vue modèle. Documentation ici (rubrique 21.2.10. "Le Web De Gestion De Session").
Si vous préférez rouler votre propre, découvrez cette codeproject la publication par le projet de Loi McCafferty: "NHibernate Meilleures Pratiques". Vers la fin, il décrit la mise en œuvre du modèle par le biais d'une coutume IHttpModule. J'ai aussi vu des posts autour de l'Internet pour mettre en œuvre le modèle sans IHttpModule, mais que peut-être ce que vous avez essayé.
Mon schéma habituel (et peut-être que vous avez déjà sauté à l'avance ici) est d'utiliser un cadre de premier. Il enlève beaucoup de maux de tête. Si il est trop lent ou ne convient pas à mes besoins, alors j'essaie de modifier la configuration ou le personnaliser. Seulement après que dois-je essayer de rouler mon propre, mais YMMV. 🙂
Ok, je vois où vous allez avec cette. Voir modifier. Comme une note de côté, si, comme je l'ai mentionné déclarant la ISession à être statique signifie qu'il va rester plus d'une demande de page (probablement).
pouvez-vous m'indiquer un implémentations sans IHttpModule? Aussi comment voulez-vous gérer les transactions et de rinçage/fermer les sessions?
OriginalL'auteur Stuart Childs
Je ne peux pas être certain (je suis un Java Hibernate gars) dans NHibernate, mais dans la Session hibernate objets ne sont pas thread-safe by design. Vous devez ouvrir et fermer une session et ne le laissez jamais hors de la portée du thread courant.
Je suis sûr que les motifs tels que "Ouvrir session de la vue" ont été mis en œuvre .Net quelque part.
L'autre question intéressante, c'est quand vous mettez un hibernate entity dans la session. Le problème ici est que la session à laquelle il est attaché sera fermé (ou devrait être) sur la demande de finition. Vous avez de la rattacher à l'entité de la nouvelle (hibernate) session si vous souhaitez naviguer non chargé des associations. Ce en lui-même provoque une nouvelle question si deux demandes essayer de le faire en même temps que quelque chose va exploser si vous essayez de joindre une entité à deux séances.
Espère que cette aide.
Gareth
OriginalL'auteur Gareth Davis
Le problème a fini par être que ma bibliothèque pour l'inversion de contrôle n'était pas de gérer les objets en cours de création dans le contexte HTTP correctement donc je recevais des références pour les objets qui ne devrait pas disponible à ce contexte. Ce fut à l'aide de Ninject 1.0, une fois que j'ai mis à jour pour Ninject 2.0 (beta) le problème a été résolu.
OriginalL'auteur John_