Question

Lorsque vous utilisez UnitOfWork de Rhino Commons (dans une UnitOfWorkApplication pour ASP-MVC), j'aime bien utiliser la classe statique du référentiel Rhino pour enregistrer des entités comme ceci:

Repository<Car>.Save(new Car(Id = 1));

Je constate que je peux alors sortir l'entité immédiatement après cet appel en utilisant:

Car car = Repository<Car>.Get(1);

Cela fonctionne bien. Cependant, lorsque j'utilise le fournisseur NHibernate Linq sur Rhino UnitOfWork, procédez comme suit:

var allCars = (from rep in UnitOfWork.CurrentSession.Linq<Car>()
               select rep).ToList();

Je reçois une liste vide. Il semble que je dois appeler UnitOfWork.Current.Flush () avant de pouvoir sortir la voiture comme ça. Je ne comprends pas pourquoi, étant donné que dans les coulisses, je suppose que les deux méthodes de récupération interrogent la même session / unité de travail. Cela signifie-t-il que vous devez appeler UnitOfWork.Current.Flush () après chaque enregistrement dans la base de données? NHibernate ne devrait-il pas pouvoir déterminer quand se vider? Ou est-ce que je comprends mal quelque chose?

Était-ce utile?

La solution

D'accord, il semble que même si un appel Get au référentiel peut utiliser le cache de session, il est donc possible de "voir" la voiture enregistrée dans le cache:

Car car = Repository<Car>.Get(1); // This works because it uses the same session

Une requête linq n'utilise PAS le cache de session:

var allCars = (from rep in UnitOfWork.CurrentSession.Linq<Car>()               
select rep).ToList(); // Does not work, even if it is in the same code block and even though it uses the same session

La meilleure pratique est donc que toute modification de la base de données (enregistrer, mettre à jour, supprimer, insérer) soit suivie de:

UnitOfWork.Session.Flush(), 

ou enveloppé dans un:

With.Transaction(delegate{
   // code here
})

ou décorez votre méthode avec [Transaction] et utilisez ATM. Cela garantira que les requêtes linq suivantes porteront sur des données mises à jour.

Autres conseils

Lorsque vous appelez Repository.Save, vous notifiez la session détenue par le référentiel afin de suivre cet objet et de synchroniser les modifications apportées à la base de données lors du prochain vidage. Tant que vous n'avez pas vidé la session, aucune modification n'est apportée à la base de données. L'objet devient cependant une partie du cache de session et sera donc renvoyé par Get (1).

Lorsque vous exécutez une requête pour renseigner une collection, la session interroge la base de données pour obtenir les résultats, sauf si elle les a déjà mis en cache. Puisque vous n'avez pas encore mis à jour la base de données, la voiture que vous avez ajoutée à la session ne fera pas partie du jeu de résultats. (< - Peut-être incorrect) Si je suis en train de lire la documentation correctement, les résultats de la requête et les entités Save () doivent être ajoutés au cache de session (premier niveau). Cela ne signifie pas nécessairement que le querystatement.List() interroge le cache après avoir ajouté les résultats de la base de données ... J'ai du mal à comprendre exactement ce qui se passe.

En passant, je pense que vous pouvez configurer la session pour qu'elle se bloque automatiquement, mais je devrais consulter la documentation.

MISE À JOUR:

Je pense que je pourrais voir ce qui se passe ici. La session par défaut FlushMode est Auto mais celle de Rhino UnitOfWork.Start() crée une session avec Commit définie sur Flush(), ce qui signifie que la session ne se vide pas automatiquement à moins que vous n'appeliez explicitement FlushMode = Auto ou ne validiez la transaction. Avec un Session.Find de UnitOfWork.CurrentSession.FlushMode = FlushMode.Auto;, NHibernate vide (parfois?) La session avant de l'interroger pour empêcher le renvoi de données obsolètes. Si j'ai raison, votre transaction de base de données ressemble à quelque chose comme:

SELECT * FROM Car

INSERT INTO Car (...) VALUES (...)

Quand le vidage automatique semble un peu ambigu dans la documentation / les blogs que j'ai lus ... la réponse la plus commune est qu'il le fait avec <=> le vidage & "; parfois; &"; bien que garantisse que <=> ne renverra jamais de données périmées. Étant donné que NHibernate Linq ne fait que créer une requête de critères, il se peut que le rinçage automatique ne soit pas déclenché (peut-être que cela a été corrigé maintenant ... difficile à savoir).

Il me semble donc que dans votre cas, vous souhaitez vider le disque après votre sauvegarde, car vous souhaitez récupérer immédiatement les résultats de votre sauvegarde. Dans une unité de travail plus petite où vous ne mettiez à jour que des entités, un seul Commit () conviendrait. Peut-être que <=> pourrait faire l'affaire, mais le fait que UOW Factory définisse explicitement le mode sur Commit (Commit) semble vous inciter à réfléchir réellement aux limites de votre UOW.

Merci à Stuart Childs, je suppose qu’il a raison de penser que le problème pourrait provenir du fournisseur NHibernate Linq. Je ne suis pas sûr de ce qu'il fait en coulisse, mais il se peut que vous utilisiez une session différente. Si c'est le cas, il est alors logique que je doive vider le référentiel avant que la requête Linq ne le "voie". Il est temps de regarder à travers le code source, mais on m'a dit que cela me ferait fondre la tête en essayant de le comprendre!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top