Субоптимальные запросы в отношениях «многие ко многим» с HQL - PullRequest
1 голос
/ 07 июля 2011

У меня есть две сущности, Location и Industry, и таблица ссылок между ними. Я настроил отношения «многие ко многим» в обоих направлениях между двумя объектами.

В поисковом запросе я пытаюсь выбрать местоположения, связанные со списком отраслей.

После нескольких дней попыток изменить API критериев я решил перейти на HQL и отказаться от API критериев. Но даже это не подходит для меня - кажется, независимо от того, пишу ли я вручную этот HQL-запрос или позволяю API критериев сделать это, я получаю тот же результат.

Мне удалось получить правильный результат двумя способами - вот так:

var q = Data.Query("select distinct loc from Location loc join loc.Industries ind where ind in (:ind)");

q.SetParameterList("ind", new Industry[] { Data.GetIndustry(4), Data.GetIndustry(5) });

И (лучше) вот так:

var q = Data.Query("select distinct loc from Location loc join loc.Industries ind where ind.id in (:ind)");

q.SetParameterList("ind", new int[] { 4, 5 });

К сожалению, оба результата приводят к неоптимальному запросу:

select distinct
  location0_.Id as Id16_,
  location0_.Name as Name16_,
  (etc.)
from Location location0_
  inner join LocationIndustry industries1_
    on location0_.Id=industries1_.LocationId
  inner join Industry industry2_
    on industries1_.IndustryId=industry2_.Id
where
  industry2_.Id in (? , ?)

Почему дополнительное объединение?

Разве NH не достаточно умен, чтобы знать, что свойство Industry.Id, являющееся единственным свойством Industry, вовлеченным в запрос, хранится в таблице ссылок LocationIndustry, и нет необходимости в дополнительном соединении с таблицей Industry сама

Или я что-то не так делаю?

В идеале, наиболее интуитивно понятным для меня было бы написать:

from Location loc where loc.Industries in (:ind)

Это не работает - выдает ошибку и говорит, что не знает о свойстве Industries. Я думаю, потому что Industries, будучи «свойством» в терминах программирования, на самом деле являются «отношениями» в терминах СУБД.

Какой самый простой и эффективный способ написать этот запрос на HQL?

Спасибо!

1 Ответ

2 голосов
/ 07 июля 2011

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

Вы можете избежать этого, используя промежуточный класс, но это будет означать, что вам потребуется структура класса, подобная этой:

public class Industry {
    //Other stuff
    public virtual List<LocationIndustry> LocationIndustries {get; set:;}
}

public class LocationIndustry {
    public virtual Location Location {get; set;}
    public virtual Industry Industry {get; set;}
}

public class Location {
    //normal stuff
    public virtual IList<LocationIndustry> LocationIndustries {get; set;}
}

Затем вы можете запросить класс LocationIndustry и избежать объединения с Location.

...