views:

281

answers:

1

I've got a Criteria Query for a social networking site. A Person object has a collection of Friends (also person objects). The query grabs the first N friends, but I also want to eager load an associated object MainProfileImage and then a subsequent associated object MediumThumbnail.

I can do this in HQL easily:

select friends from Person person inner join person.Friends friends inner join fetch friends.MainProfileImage image inner join fetch image.MediumThumbnail where person = :person1 order by friends.LatestLogin desc

Here's My Criteria effort. For some reason this doesn't return anything!

public static IList<Person> GetFriends(Person person, int count)
{
    Person personAlias = null;
    Person friendAlias = null;

    ICriteria criteria = NHibernateSessionManager.Instance.GetSession()
        .CreateCriteria(typeof (Person), () => personAlias)
        .CreateCriteria(() => personAlias.Friends, () => friendAlias, JoinType.LeftOuterJoin)
        .CreateCriteria(() => friendAlias.MainProfileImage, JoinType.InnerJoin)
        .CreateCriteria(() => friendAlias.MainProfileImage.MediumThumbnail, JoinType.InnerJoin)
        .AddOrder(() => personAlias.LatestLogin, Order.Desc)
        .Add<Person>(p => p.ID == person.ID)
        .SetMaxResults(count);
    return criteria.List<Person>();
}
+2  A: 

I believe that the order of your statements causes the query to generate the not desired SQL you are getting (hence no results). Here is how it should be:

public static IList<Person> GetFriends(Person person, int count)
{
    Person personAlias = null;
    Person friendAlias = null;

    ICriteria criteria = NHibernateSessionManager.Instance.GetSession()
        .CreateCriteria(typeof (Person), () => personAlias)
        .CreateCriteria(() => personAlias.Friends, () => friendAlias, JoinType.LeftOuterJoin)
        .Add<Person>(p => p.ID == person.ID)
        .CreateCriteria(() => personAlias.MainProfileImage, JoinType.InnerJoin)
        .CreateCriteria(() => personAlias.MainProfileImage.MediumThumbnail, JoinType.InnerJoin)
        .AddOrder(() => personAlias.LatestLogin, Order.Desc)
        .SetMaxResults(count);
    return criteria.List<Person>();
}

Furthermore by your description it is not clear from which association you want to get the MainProfileImage and MediumThumbnail data from. As you are using it in your Criteria statement you are asking the data to come from the main Person object whose friends you are getting as you are using the friendsAlias. I have changed it to use the personAlias instead as I believe this is where you mean to associate the data from.

tolism7
That worked perfectly, thanks! I did have to change friendAlias to personAlias - which is something I am having trouble getting my head around but it worked! Please update your answer to reflect this. Thanks again!
reach4thelasers
Answer updated! To get your head around the confusion with the aliases try to verbalise the query. What we are saying in the Criteria query is "get me all person objects that are friends with the given person object whose ID I have" that means you are starting your query from the elements in the given person object's friends collection. That is why personAlias belongs to your results (friends of the given oerson object) and the friendsAlias belings to the given person object. The confusion also comes from the unfortunate naming of the aliases.
tolism7