2010-03-10 4 views
0

J'ai un modèle d'objet d'essai simple dans lequel il y a des écoles, et une école a une collection d'étudiants.Collections nHibernate et critères d'alias

Je voudrais récupérer une école et tous ses élèves qui ont dépassé un certain âge.

je porte la requête suivante, qui obtient une école donnée et les enfants qui sont au-dessus d'un certain âge:

public School GetSchoolAndStudentsWithDOBAbove(int schoolid, DateTime dob) 
    { 
     var school = this.Session.CreateCriteria(typeof(School)) 
     .CreateAlias("Students", "students") 
     .Add(Expression.And(Expression.Eq("SchoolId", schoolid), Expression.Gt("students.DOB", dob))) 
     .UniqueResult<School>(); 

     return school; 
    } 

Tout cela fonctionne très bien et je peux voir la requête va à la base de données et retourner le nombre attendu de lignes.

Cependant, lorsque je réalise une des conditions suivantes, il me donne le nombre total d'élèves de l'école donnée (quelle que soit la requête précédente) en exécutant une autre requête:

 foreach (Student st in s.Students) 
     { 
      Console.WriteLine(st.FirstName); 
     } 

     Assert.AreEqual(s.Students.Count, 3); 

Quelqu'un peut-il expliquer pourquoi ?

+0

semble que la requête de critères exécute 2 requêtes. celui qui exécute WHERE (this_.SchoolId = @ p0 et students1_.DateTime> @ p1); @ p0 = '1', @ p1 = '01/01/1997 00:00:00 ' rejoindre l'école et l'élève. puis celui qui obtient juste l'école requise – Youeee

Répondre

1

Malheureusement, s.Students ne contiendra pas vos "résultats recherchés". Vous devrez créer une requête distincte pour les Etudiants afin d'atteindre votre objectif.

foreach(var st in s.Students.Where(x => x.DOB > dob)) 
    Console.WriteLine(st.FirstName); 

Attention: Cela va encore faire deuxième voyage à la DB en fonction de votre cartographie, et il sera toujours récupérer tous les élèves.

Je ne suis pas sûr, mais vous pourriez éventuellement utiliser Projections pour faire tout cela en une seule requête, mais je ne suis en aucun cas un expert en la matière.

0

Vous avez la possibilité de filtrer des données. S'il y a une seule instance de la requête, l'option mxmissle serait le meilleur choix.

Nhibernate Filter Documentation

Les filtres n'ont il utilise, mais en fonction de la version que vous utilisez, il peut y avoir des problèmes où les collections filtrées ne sont pas mises en cache correctement.

2

Vous avez fait votre requête sur la classe School et vous avez restreint vos résultats, pas sur les objets associés mappés.

Maintenant, il existe plusieurs façons de le faire. Vous pouvez créer un filtre statique comme l'a dit IanL, mais ce n'est pas vraiment flexible. Vous pouvez simplement itérer la collection comme mxmissile mais ce qui est laid et lent (surtout compte tenu des considérations de chargement paresseux)

Je fournirais 2 solutions différentes: Dans la première vous maintenez la requête que vous avez et vous tirer un filtre dynamique la collection (le maintien d'une collection paresseux chargé) et de faire un aller-retour à la base de données:

var school = GetSchoolAndStudentsWithDOBAbove(5, dob); 
IQuery qDob = nhSession.CreateFilter(school.Students, "where DOB > :dob").SetDateTime("dob", dob); 
IList<Student> dobedSchoolStudents = qDob.List<Student>(); 

dans la deuxième solution juste aller chercher l'école et les élèves d'un seul coup:

object result = nhSession.CreateQuery(
    "select ss, st from School ss, Student st 
    where ss.Id = st.School.Id and ss.Id = :schId and st.DOB > :dob") 
    .SetInt32("schId", 5).SetDateTime("dob", dob).List(); 

ss est un objet scolaire et st est une collection d'étudiants.

Et cela peut certainement être fait en utilisant les critères utilisez requête vous maintenant (en utilisant les projections)

Questions connexes