session.CreateCriteria(typeof(Contact))
.Add(Expression.Eq("Name", "Bob")
.SetFetchMode("Emails", FetchMode.Eager)
.CreateCriteria("Emails")
.Add(Expression.Eq("EmailAddress", "Bob@hotmail.com"))
.List();
Note: FetchMode.Eager is equivalent to FetchMode.Join.
The resulting SQL will include a Join to Emails as expected, the resultset returned by the database is OK, but within the object model Contact.Emails is not going to be populated with data. Which means once Contact.Emails is being accessed in code, lazy loading occurs, which IMHO is undesired behavior. This is not the case when
CreateCriteria("Emails")
.Add(Expression.Eq("EmailAddress", "Bob@hotmail.com"))is omitted.
The bug report was closed without fix, but including a comment that "According to Hibernate guys this is correct behavior" and a link to Hibernate bug report #918.
Anyway, interestingly this can be worked around either by phrasing the same query in HQL, or by applying an outer Join on the child Criteria (which of course is somewhat semantically different, but leads to the same results in this case):
session.CreateCriteria(typeof(Contact))
.Add(Expression.Eq("Name", "Bob")
.CreateCriteria("Emails", JoinType.LeftOuterJoin)
.Add(Expression.Eq("EmailAddress", "Bob@hotmail.com"))
.List();
On a related topic, eagerly joining several child associations has the drawback that the resultset consists of a cartesian product over all children - lots of rows with duplicate data. Let's say there are three child associations A, B and C with 10 rows each for a given parent row, joining all three associations will blast up the resultset to 1 x 10 x 10 x 10 = 1000 rows, when only 1 + 10 + 10 + 10 = 31 rows would be needed.
And while those duplicates will only lead to duplicate references in the object model (and not to duplicate instances), and even those duplicate references can be eliminated again by using Maps or Sets for child collections, these Joins impose a severe performance and memory drawback on the database resp. ADO.NET level.
Of course one could simply issue N single select statements, one for each table, with equaivalent where-clauses. But that implies N database roundtrips as well. Not so good.
The means to avoid this are Hibernate Criteria- and HQL-MultiQueries. Gabriel Schenker has posted a really nice article on MultiQueries with NHibernate.