This is for a M:N relationship, with the collection being mapped in NHibernate as a Set.
The criteria query we were using previously "worked" but it did not populate the Skills collection properly, in that only the first/looking-for skill was brought down, even if the employee had multiple skills.
I changed it to a LINQ query and it fixes the issue, properly fetching all the skills of that employee.
Dim sId = 1 ' Just to have one for example
Dim lstEmployees = Session.CreateCriteria(Of Employee)() _
.CreateAlias("Skills", "s", NHibernate.SqlCommand.JoinType.LeftOuterJoin) _
.Add(Expression.Or(Expression.Eq("PrimarySkillId", sId),
Expression.Eq("s.Id", sId))) _
.SetResultTransformer(New DistinctRootEntityResultTransformer()) _
.List(Of Employee)()
' Returns correct employees but only their first skill in the Skills collection, even if they have more than one
Dim lstEmployees = (From e In Session.Query(Of Employee)()
Where e.PrimarySkillId =sId OrElse e.Skills.Any(Function(s) s.Id = sId)
Select e Distinct).Fetch(Function(e) e.Skil开发者_如何学Pythonls).ToList()
' Returns correct employees and their Skills collection contains all of their skills
Does anyone understand what's different about the two seemingly-equivalent queries?
Off the bat, the first query is doing the distinct separation after retrieving all rows, while the second query actually does a select distinct ...
. What's likely happening is that it hydrates the Employee model with just the one Skill retrieved
To make the first query actually do a select distinct ...
you will need to use projections.
Something like
Session.CreateCriteria(Of Employee)() _
.CreateAlias("Skills", "s", NHibernate.SqlCommand.JoinType.LeftOuterJoin)
.Add(Expression.Or(Expression.Eq("PrimarySkillId", sId),
Expression.Eq("s.Id", sId))) _
.SetProjection(Projections.Distinct("Id")) _
.SetFetchMode("s", FetchMode.Eager)
may work. Alternatively you can try to just set the fetch mode with the DistinctRootEntityResultTransformer
Session.CreateCriteria(Of Employee)() _
.CreateAlias("Skills", "s", NHibernate.SqlCommand.JoinType.LeftOuterJoin)
.Add(Expression.Or(Expression.Eq("PrimarySkillId", sId),
Expression.Eq("s.Id", sId))) _
.SetResultTransformer(Transformers.DistinctRootEntityResultTransformer) _
.SetFetchMode("s", FetchMode.Eager)
精彩评论