2010-11-06 10 views
1

Quelle est la bonne manière de référencer des entités qui étaient déjà persistées dans une session différente, mais restaient inchangées dans la mémoire après la fermeture d'une session? Une fois que NH persiste une entité dans une seule session et que cette session est fermée, je dois la reprendre dans une nouvelle session afin de la référencer dans d'autres entités transitoires. Ou, je peux appeler Session.Lock sur la nouvelle instance de session et informer NH que cette entité n'est pas transitoire. Cet élément ne devrait jamais changer pendant la durée de vie de l'application.Gérer correctement les entités transitoires dans NHibernate

Quelle serait la meilleure façon d'utiliser? Y a-t-il un autre moyen de le faire?

[Modifier]

problème est que je suis en utilisant le modèle du référentiel, et ne pas utiliser NH directement dans ma couche d'affaires. Cela signifie que j'ai également besoin d'un moyen de résumer cet appel à Session.Lock, c'est-à-dire d'avoir une méthode similaire à Session.Lock dans mon interface de référentiel. C'est un peu malodorant à mon humble avis.

+0

Pourquoi conservez-vous des entités en mémoire après la fermeture de la session? Je n'ai jamais eu besoin de faire ça. – Paco

+0

@Paco: Je crée beaucoup de nouvelles entités qui référencent des entités existantes, déjà persistées. – Groo

+0

Je veux dire pourquoi les gardez-vous en mémoire au lieu de les récupérer dans la base de données? Cela ne causera-t-il pas une base de données corrompue quand une transaction échoue? – Paco

Répondre

2

Concernant la première question. Si vous allez juste lire l'entité, vous n'avez rien à faire. Même si vous l'attribuez en tant que champ à une entité différente, vous ne devrez pas verrouiller l'enregistrement. La seule raison pour laquelle vous devez appeler ISession.Lock est lorsque vous voulez muter, puis enregistrer l'entité.

Il existe une exception, à savoir le chargement paresseux. Si l'entité a des enregistrements enfant étrangers qui n'ont pas été chargés alors que la première session était active, une exception sera levée lorsque vous tenterez d'y accéder plus tard. La façon la plus simple de se déplacer est de toucher les collections d'enfants en première session.

Si l'entité vous pose toujours des problèmes dans ces circonstances, vous pouvez ajouter un Load à votre référentiel. Vous pouvez câbler ceci à ISession.Load. Qu'est-ce que Load est de créer un proxy vide pour l'entité sans frapper la base de données. Cette entité fait partie de la session dans laquelle l'entité est chargée et peut être utilisée pour affecter des propriétés à d'autres entités. L'avantage de cette approche est qu'elle est beaucoup plus propre et qu'il est facile de se moquer des tests unitaires.

Concernant la deuxième question. Oui, vous avez raison, ça sent l'intégration de ISession.Lock dans un dépôt. Encore une fois, lorsque vous n'avez pas à muter l'entité, vous n'avez pas à vous en préoccuper. Mais, quand vous êtes, eh bien, vous devriez vraiment penser à simplement recharger l'entité à partir du dépôt et travailler sur celui-ci. Je sais que ce n'est pas aussi optimal que possible, mais cela vous permet d'économiser beaucoup de code très étrange, particulièrement dans vos tests unitaires.

Une dernière chose. Je comprends que vous parlez d'une entité qui va vivre longtemps (peut-être l'exécution complète de l'application). Vous avez à peu près trois catégories de vie: 1. pour toujours, 2. long et 3. court. La raison pour laquelle je mentionne cela est que plus d'une fois, les problèmes avec des entités qui ont une «longue» durée de vie pourraient vraiment rester connectés à une session qui a la même durée de vie. Ce n'est pas un problème d'avoir une session en vie par exemple, 5 ou 10 minutes (le temps que l'utilisateur entre des données dans un formulaire). Cela seul permettra d'économiser beaucoup de gens beaucoup d'ennuis.

Encore une note: jetez un oeil à NHibernateUtil et NHibernateProxyHelper. Ces classes peuvent vous aider à forcer le chargement des entités et des collections enfants.

+0

Merci. Cette entité ** est ** de longue durée (tout au long de la durée de vie de l'application), et la plupart des nouvelles entités qui seront conservées doivent faire référence à cette entité. Donc, chaque fois que je crée une nouvelle session afin de sauvegarder ces nouvelles entités, je dois dire à NH que cet objet a déjà été conservé - sinon il se plaint qu'il s'agit d'un objet transitoire. – Groo

+0

Une alternative consiste à ajouter des méthodes 'Load' à vos dépôts en appelant à son tour' Load' sur la session. Ensuite, vous pouvez charger l'entité dans la session en cours par son ID. La chose à propos de 'Load' est qu'il ne frappe pas la base de données, mais crée un proxy avec seulement l'ID. De cette façon, vous pouvez récupérer l'objet sans le récupérer. Lors des tests unitaires, il est beaucoup plus facile et plus propre de truquer. Mise à jour de la réponse –

+0

Ok, il semble que je faisais quelque chose de mal, parce que vous avez raison: Si je ne change pas l'entité et que je l'attribue à une entité différente, je n'ai rien à faire. – Groo

3

La meilleure approche consiste à activer la mise en cache de second niveau et à rendre l'objet éligible à la mise en cache.Si vous faites cela, vous pouvez le récupérer dans vos méthodes de dépôt, mais il sera récupéré du cache au lieu de la base de données.

+0

Merci, c'est une idée soignée aussi. Avez-vous une recommandation sur quel fournisseur de cache de deuxième niveau je devrais utiliser? – Groo

+0

Si vous utilisez SQL Server, je commencerais par SysCache2 car il prend en charge SqlDependencies. Pas que j'ai jamais eu besoin de cette fonctionnalité. –

+0

Cela fait un moment depuis la dernière réaction, mais je voudrais simplement souligner que SysCache2 est génial, mais aussi que Second Level Caching est une fonctionnalité plutôt obscure en matière de documentation. Un bon conseil: si vous configurez VS correctement, vous pourrez déboguer NH, ce qui peut être très révélateur si vous n'êtes pas sûr de ce qui se passe: http://www.symbolsource.org/Public/Home/VisualStudio –

Questions connexes