1

Я пытался выяснить, почему этот запрос с просьбой о менеджере и его или ее команде возвращает только первую запись коллекции Team. По-видимому, это потому, что у меня был FirstOrDefault в конце запроса. Я был под впечатлением, что FirstOrDefault применимо к запросу в целом, но похоже, что оно применяется и к коллекции Team.Почему эти два Свободных nHibernate-запроса дают разные результаты?

Оригинал запроса (показан только первый член в команде):

session.Query<IEmployee>() 
       .Where(p => p.PersonalNumber == PersonalNumber) 
       .Fetch(p => p.Team) 
       .Fetch(p => p.Manager) 
       .FirstOrDefault(); 

Новый запрос, который возвращает полную команду:

session.Query<IEmployee>() 
       .Where(p => p.PersonalNumber == PersonalNumber) 
       .Fetch(p => p.Team) 
       .Fetch(p => p.Manager) 
       .ToList().FirstOrDefault(); 

Что бы правильный способ сформулировать этот запрос? Моя потребность в обходном пути подразумевает, что я не делаю этого правильно.

фона - отображения:

Это основной иерархическая связь с менеджером будучи IEmployee и Team будучи IList из IEmployee.

References(x => x.Manager).Column("ManagerId"); 
HasMany(x => x.Team) 
       .AsList(index => index.Column("TeamIndex")) 
       .KeyColumn("ManagerId"); 
+0

Вы можете сказать, из сгенерированного SQL, как это происходит потому, что запрос проблема генерирует SQL «FETCH NEXT, 1 ROWS ONLY», который предположительно означает, что только первый присоединиться к записи будут возвращены. Мне непонятно, как заставить FirstOrDefault правильно работать с Fetch. – kasey

ответ

1

я боролся с той же проблемой. Для меня это произошло при обновлении с NH 3.1 -> 3.3. Проблема в том, что с Linq NHibernate 3.3 генерирует SQL-запрос с надписью «Top (1)», эффективно убивая «выборку» части запроса. Я решил это, переключившись с Linq на QueryOver. Я считаю, что это будет работать:

session.QueryOver<IEmployee>() 
       .Where(p => p.PersonalNumber == PersonalNumber) 
       .Fetch(p => p.Team) 
       .Fetch(p => p.Manager) 
       .SingleOrDefault(); 
+0

Интересно, это то, что я заметил и после некоторых экспериментов (см. Мой ответ ниже), и да, я использую nHibernate 3.3. Интересно, должен ли исходный синтаксис вызывать какое-то исключение, говорящее, что оно неверно. – kasey

3
session.Query<IEmployee>() 
      .Where(p => p.PersonalNumber == PersonalNumber) 
      .Fetch(p => p.Team) 
      .Fetch(p => p.Manager) 
      .FirstOrDefault(); 

В этом опрашивать FirstOrDefault работает на базе, как вы ожидали.

session.Query<IEmployee>() 
      .Where(p => p.PersonalNumber == PersonalNumber) 
      .Fetch(p => p.Team) 
      .Fetch(p => p.Manager) 
      .ToList().FirstOrDefault(); 

В этом запросе ToList работает с базой данных. Все позади работает над результатом ToList. Таким образом, FirstOrDefault получает FirstOrDefault из набора результатов ToList. Чтобы получить тот же результат, вам нужно будет добавить заказ к вашему запросу. Sql не предоставляет тот же порядок результирующего набора, когда вы делаете выбор без ордера. Порядок в результате ToList отличается от внутреннего порядка в первом запросе.

+0

Извините, я не совсем понимаю. Как бы порядок набора результатов (который всегда будет содержать только 1 IEmployee, PersonalNumber уникален) влияет на количество элементов в коллекции Employee.Team? – kasey

0

Проблема в том, что я прошу декартово произведение (используя Fetch), но также используя FirstOrDefault; из сгенерированного SQL я вижу, что эта комбинация не работает, так как вы получаете только первую строку декартова продукта (сгенерированный SQL: «FETCH NEXT 1 ROWS ONLY»).

Мне нужно будет написать другой тип запроса, если я хочу это сделать, или просто использовать обходной путь ToList, который в этом случае не приносит большого вреда, поскольку я ожидаю только одного результата из базы данных ,

Пример решения:

session.QueryOver<IEmployee>() 
       .Where(p => p.PersonalNumber == PersonalNumber) 
       .Fetch(p => p.Team).Eager 
       .Fetch(p => p.Manager).Eager 
       .SingleOrDefault();