2010-12-01 4 views
0

Question: Comment obtenir un critère de chargement chargé pour renvoyer des résultats paginés sur l'entité racine avec toutes les collections enfant définies fetchmode = eager.NHibernate paging critères avec fetchmode désireux. (utilisation de NH fluide)

J'essaie d'obtenir un ensemble de résultats paginés de 10 éléments avec des collections enfants chargées. Le problème est que la requête fait un top 10 sélectionné autour de la sélection complète. Le fait de renvoyer seulement les 10 premiers résultats, y compris tous les enregistrements joints. Si la première entité a 10 objets enfants, alors mon jeu de résultats renverra 1 entité avec 10 objets enfants chargés. J'ai besoin des entités et des collections d'enfants retournés hydratés (paresseux). Si je désactive le chargement paresseux et exécute cette requête, j'obtiens la requête n + 1 pour chaque associé dans le jeu de résultats.

Ceci est mon processus de requête de base:

criteria = context.Session.CreateCriteria<Associate>(); 
criteria.SetMaxResults(10); //hardcoded for testing 
criteria.SetFirstResult(1); //hardcoded for testing 
criteria.SetFetchMode("Roles", NHibernate.FetchMode.Eager); 
criteria.SetFetchMode("Messages", NHibernate.FetchMode.Eager); 
criteria.SetFetchMode("DirectReports", NHibernate.FetchMode.Eager); 
criteria.SetResultTransformer(new DistinctRootEntityResultTransformer()); 
return criteria.List<Associate>(); 


public AssociateMap() 
    { 
     ReadOnly(); 
     Id(x => x.AssociateId); 
     Map(x => x.FirstName); 
     Map(x => x.LastName); 
     Map(x => x.ManagerId); 
     Map(x => x.Department); 
     Map(x => x.Email); 
     Map(x => x.JobTitle); 

     Map(x => x.LastFirstName).Formula("LTRIM(RTRIM(LastName)) + ', ' + LTRIM(RTRIM(FirstName))"); 

     HasMany(x => x.Messages).KeyColumn("AssociateId").Inverse().Cascade.All(); 
     HasMany(x => x.Roles).Element("RoleKey"); 
     HasMany(x => x.DirectReports).KeyColumn("ManagerId").Cascade.None().ForeignKeyConstraintName("FK_Associate_Manager"); 
     //HasMany(x => x.DirectReports).Element("ManagerId").CollectionType(typeof(Domain.Associate)); 


    } 

Répondre

3

La solution a fini par utiliser une sous-requête pour définir les résultats max. J'ai ajouté la sous-requête en utilisant Subqueries.PropertyIn. Je clone les "critères" à "limiteur" parce que j'ai ajouté l'expression de critère dans le code non montré. J'ai donc besoin de cloner ces critères dans la sous-requête afin que le top 10 select soit dans l'instruction "IN". Maintenant, je peux charger les collections enfants et ajouter la pagination à l'entité racine pour récupérer 10 enties sans problèmes avec cartésien ou n + 1. Je vais essayer de faire un suivi avec un code plus complet et organisé.

//criteria = context.Session.CreateCriteria<Associate>(); 
//changed criteria to DetachedCriteria. 
criteria = DetachedCriteria.For<Associate>(); 

DetachedCriteria limiter = CriteriaTransformer.Clone(criteria); 
limiter.SetProjection(Projections.Id()); 
limiter.SetMaxResults(10); 
criteria.Add(Subqueries.PropertyIn("AssociateId", limiter)); 

criteria.SetFetchMode("Roles", NHibernate.FetchMode.Eager); 
criteria.SetFetchMode("Messages", NHibernate.FetchMode.Eager); 
criteria.SetFetchMode("DirectReports", NHibernate.FetchMode.Eager); 
criteria.SetResultTransformer(new DistinctRootEntityResultTransformer()); 
return criteria.List<Associate>(); 
+0

J'aime cette solution. –

+0

+1 pour avoir partagé la réponse. – kerzek

Questions connexes