Force paresseux entité à la charge réelle de l'instance
J'ai un proxy pour un paresseux entité qui a été créée dans la session par le chargement d'un enfant de l'entité. Une extraction ultérieure sur l'entité mère ne retourne que le NH proxy. J'ai besoin de l'instance réelle pour vérifier le type (l'entité qui a rejoint les sous-classes). Quelque chose doit m'échapper, mais je ne peux pas trouver un moyen de le faire. Session.Refresh(proxy) ne semble pas aider, ni toute la saveur de HQL que j'ai essayé.
Peut aider quelqu'un?
- Pourriez-vous montrer comment votre domaine des objets et les requêtes HQL que vous avez essayé jusqu'à présent?
- Je ne suis pas sûr que je peux présenter à la quantité d'informations dans ce format. Êtes-vous ce qui implique qu'il doit être possible d'écrire une requête HQL qui ne tient pas compte de contrepartie des procurations dans le cache?
Vous devez vous connecter pour publier un commentaire.
Pour forcer un proxy être récupérées à partir de la base de données, vous pouvez utiliser le
NHibernateUtil.Initialize(proxy)
méthode, ou d'accéder à une méthode/propriété de la procuration.Pour vérifier si un objet est initialisé ou non, vous pouvez utiliser le
NHibernateUtil.IsInitialized(proxy)
méthode.Mise à jour:
Pour supprimer un objet de la cache de session, utilisez la
Session.Evict(obj)
méthode.D'infos sur
Evict
et d'autres méthodes pour la gestion du cache de session peut être trouvé dans chapitre 14.5 de la NHibernate docs.À mon avis, plutôt que de résoudre ce problème, vous devriez plutôt repenser la conception de votre. Êtes-vous absolument sûr, que vous ne pouvez pas utiliser le polymorphisme dans cette situation - soit directement, prendre de l'entité responsable de l'opération que vous tentez d'accomplir ou d'utiliser des habitudes des visiteurs. Je suis tombé sur cette question à quelques reprises et toujours décidé à changer de design - il entraîné dans le code plus clair. Je vous suggère de faire de même, sauf si vous êtes absolument sûr que le fait de compter sur type est la meilleure solution.
Le problème
Afin de disposer d'exemple avec au moins une certaine ressemblance avec le monde réel, supposons que vous avez entités suivantes:
Il avait naturellement une petite partie de beaucoup plus grand modèle. Et maintenant, vous êtes confronté à un problème: pour chaque type de béton de l'Opération, il y a une autre façon de l'afficher:
Simple, d'une surcharge de méthodes de travail dans le cas simple:
Malheureusement, les méthodes surchargées sont liés au moment de la compilation, donc dès que vous vous en présenter un tableau/liste/whatever des opérations, seulement un générique (Fonctionnement) surcharge sera appelée.
Il y a deux solutions à ce problème, et les deux ont des inconvénients. Vous pouvez introduire un résumé/méthode virtuelle dans l'Opération pour imprimer les informations de flux choisi. Mais ce sera un mélange de l'INTERFACE utilisateur préoccupations dans votre modèle, ce qui n'est pas acceptable pour vous (je vais vous montrer comment pouvez-vous améliorer cette solution pour répondre à vos attentes dans un instant).
Vous pouvez également créer beaucoup de ifs dans la forme de:
Cette solution est laid et sujettes à erreur. Chaque fois que vous ajouter/modifier/supprimer le type de fonctionnement, vous devez aller à travers chaque endroit où vous avez utilisé ces hack et de le modifier. Et si vous manquez un seul endroit, vous aurez probablement seulement être capable d'attraper qu'à l'exécution, pas de stricts contrôles de compilation de certaines des erreurs (telles que le manque d'un sous-type).
En outre, cette solution échoue dès que vous introduisez tout type de proxy.
Comment proxy fonctionne
Le code ci-dessous est TRÈS simple proxy (dans cette mise en œuvre, il est même en tant que décorateur de modèle, mais ces modèles ne sont pas les mêmes en général. Il faudra un code supplémentaire pour distinguer ces deux modèles).
Comme vous pouvez le voir - il y a une seule classe de proxy pour l'ensemble de la hiérarchie. Pourquoi? Parce que vous devez écrire votre code dans un sens qui ne dépendent pas du type de béton uniquement sur l'abstraction. Cette procuration peut différer de l'entité de chargement dans le temps - peut-être que vous ne l'utilisez pas du tout? Peut-être que vous allez utiliser seulement 2 de 1000 entités? Pourquoi les charger ensuite?
Donc NHibernate utilise un proxy comme ci-dessus (beaucoup plus sophistiqué, tout de même) de reporter l'entité de chargement. Il pourrait créer 1 proxy par sous-type, mais il détruirait tout l'objet de lazy loading. Si vous regardez soigneusement à la façon dont NHibernate magasins de sous-classes, vous verrez, que, pour déterminer quel type d'entité, vous devez le charger. Il est donc impossible d'avoir béton procurations - vous ne pouvez avoir le plus abstrait, OperationProxy.
Bien la solution avec les fi c'est moche - c'était une solution. Maintenant, quand vous avez mis en place des procurations à votre problème - il n'est plus de travail. Cela nous laisse avec des polymorphes de la méthode, ce qui est inacceptable en raison du mélange de l'INTERFACE utilisateur la responsabilité de votre modèle. Nous allons remédier à cela.
Inversion de la dépendance et des habitudes des visiteurs
D'abord, nous allons jeter un oeil à la façon dont la solution avec des méthodes virtuelles ressemblerait (juste ajouté du code):
Et maintenant, lorsque vous composez le:
tout fonctionne comme un charme.
Afin de supprimer cette INTERFACE utilisateur de la dépendance dans le modèle, nous allons créer une interface:
Nous allons modifier le modèle à dépendre de cette interface:
Et maintenant créer une mise en œuvre - ConsoleOutputOperationVisitor (j'ai supprimé PrintInformation méthodes):
Ce qui se passe ici? Lorsque vous appelez Accepter d'exploitation, et de passer d'un visiteur, la mise en œuvre de l'accepter, sera appelé, le cas échéant surcharge de la Visite de la méthode sera invoquée (compilateur peut déterminer le type de "ce"). Si vous combinez la "puissance" de méthodes virtuelles et les surcharges approprié de la méthode appelée. Comme vous pouvez le voir - maintenant, référence de l'INTERFACE utilisateur, ici, le modèle ne dépend que de l'interface, ce qui peut être inclus dans le modèle de la couche.
Alors maintenant, pour faire ce travail, une implémentation de l'interface:
Et code:
Je suis bien conscient que ce n'est pas une solution parfaite. Vous aurez encore à modifier l'interface et les visiteurs à mesure que vous ajoutez de nouveaux types. Mais vous obtenez moment de la compilation, de vérification et de ne jamais manquer de rien. Une chose qui serait très difficile à obtenir à l'aide de cette méthode est d'obtenir enfichables sous - types- mais je ne suis pas convaincu que cela est valable un scénario de toute façon. Vous aurez également à modifier ce modèle pour répondre à vos besoins dans le béton scénario, mais je vais laisser cela à vous.
La désactivation de paresseux, le chargement de la force de l'instance elle-même à être retournés au lieu de la NHibernate Proxy.
par exemple..
de cartographie.Pas.LazyLoad();
ou
Depuis le proxy est dérivée de la classe d'entité, vous pouvez probablement juste de vérifier entité.GetType().BaseType pour obtenir votre type défini.