Почему эти два запроса NHibernate дают разные результаты? - PullRequest
0 голосов
/ 01 июня 2011

Это для отношения M: N, когда коллекция отображается в NHibernate как набор.

Критерий запроса, который мы использовали ранее, «работал», но он не заполнил коллекцию навыков должным образом, вчто только первый / искомый навык был сброшен, даже если у сотрудника было несколько навыков.

Я изменил его на запрос LINQ, и он исправляет проблему, правильно выбирая все навыки этого сотрудника.

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.Skills).ToList()

' Returns correct employees and their Skills collection contains all of their skills

Кто-нибудь понимает, чем отличаются эти два, казалось бы, эквивалентных запроса?

1 Ответ

0 голосов
/ 02 июня 2011

Безразлично, первый запрос выполняет четкое разделение после извлечения всех строк, в то время как второй запрос фактически выполняет select distinct .... Вероятно, происходит то, что она гидратирует модель Employee только одним полученным навыком

Чтобы первый запрос действительно сделал select distinct ..., вам нужно использовать проекции.

Что-то вроде

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)

может работать. В качестве альтернативы вы можете попробовать установить режим выборки с помощью 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)
...