Запрос выбора HQL для сопоставленной сущности @ManyToMany приводит к неверному синтаксису SQL - PullRequest
0 голосов
/ 17 июня 2019

Здесь есть несколько вопросов о запросах к отображенным таблицам HQL «многие ко многим», но я немного посмотрел и не видел этой.

У меня есть две таблицы в отношениях «многие ко многим» с исходными и целевыми таблицами, сопоставленными как сущности, и взаимосвязью @ManyToMany, определенной между ними, настроенной так, как это обычно рекомендуется.

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

Вот примеры определений классов:

@Entity
public class This {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    protected Long id;

    @Column
    protected Long otherId;

    @ManyToMany
    @JoinTable(joinColumns = {@JoinColumn(name = "this_id")},
        inverseJoinColumns = {@JoinColumn(name = "that_id")})
    private List<That> thats;

    // getters and setters
}

и

@Entity
public class That {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "name", unique = true)
    private String name;

    // getters and setters
}

HQL это:

select t.id,t.thats from This t where t.otherId=13

А вот SQL, который получается:

select
    this0_.id as col_0_0_,
    . as col_1_0_,
    that2_.id as id1_59_,
    that2_.name as name2_59_ 
from
    this this0_ 
inner join
    this_thats thats1_ 
        on this0_.id=thats1_.this_id 
inner join
    that that2_ 
        on thats1_.that_id=that2_.id 
where
    this0_.other_id=13

Как видите, 2-й столбец в предложении select недопустим, он выглядит так, как будто пытается создать столбец, но не использует допустимое имя или псевдоним столбца и несколько неожиданно создает недопустимый оператор SQL синтаксис, который терпит неудачу, когда это выполнено. Я прошел через код генерации SQL и включил ведение журнала трассировки, но не могу понять, что он пытается сделать или как это исправить.

Если я удаляю второй столбец, этот запрос выполняется нормально и возвращает именно те данные, которые я ищу. В качестве альтернативы я рассмотрел реализацию этого в нативном SQL, но я бы хотел этого избежать и придерживаться HQL, если это возможно, для согласованности в остальной части проекта.

Другой вариант, который я пробовал, был select t,t.thats .... Это произвело действительный запрос, но, не показанный в этом примере, он выдал намного больше запросов для других отношений, которые охотно выбираются из сущности This, что также снижает производительность. Мне действительно нужно выбрать только один ключевой столбец из исходной таблицы.

Действительно минимальный запрос, который бы возвращал нужные мне данные, вообще не должен был бы попадать в таблицу That, он был бы только в таблице This и неявной не отображенной таблице this_thats, которая была создана и управляется JPA, но не отображается на объект. Я попытался сопоставить это с сущностью, чтобы я мог запросить его, но Hibernate пожаловался при запуске, что эта таблица была отображена дважды. Если есть какой-то другой способ добраться до этой таблицы и запросить ее напрямую, я был бы рад сделать это.

Это с hibernate-jpa-2.1, который, как я знаю, является старой версией, но это устаревшая система в производстве. Если бы обновление JPA помогло, я бы обдумал это, но сначала хотел бы понять причину, если это возможно.

Ответы [ 4 ]

0 голосов
/ 18 июня 2019

Я разобрался с ответом, который выкладываю, чтобы помочь всем, кто сталкивается с этим.join должен быть явным в HQL следующим образом:

select t.id,th from This t join t.thats th where t.otherId=13

Очевидно, что Hibernate не может определить правильный оператор выбора без этого.

0 голосов
/ 17 июня 2019

Еще одна попытка: возможно, проблема в том, что вы не можете получить список в виде одной строки результата оператора SQL select. Возможно, вам не нужно выбирать второй столбец, потому что

    List<That> thats 

заполняется автоматически в спящем режиме.

0 голосов
/ 17 июня 2019

То, что вы говорите или пытаетесь сделать, не имеет смысла.t.thats - это коллекция, поэтому вы не можете вернуть ее как часть строки.Вы должны думать больше об объектно-ориентированном с JPA.Кроме того, JPA 2.1 не особенно устарел, поэтому проблем не должно быть.Итак, рабочий запрос, который предварительно выбирает коллекцию thats, выполняется следующим образом:

This t2 = em.createQuery("from This t left outer join fetch t.thats where t.otherId = 12", This.class).getSingleResult();
System.out.println("" + t2 + t2.getThats());

Этот запрос сообщает JPA, что вы хотите получить This и любые связанные thats в одном запросе.

Вы заявляете, что хотите только содержимое таблицы соединения ThisThat.Эта таблица имеет только ids отношений.По какой-то причине вы можете захотеть идентификаторы, чтобы вы могли получить thats позже.Справедливо, но, как вы сказали, вам нужно будет создать таблицу соединений как отдельную сущность, а затем использовать запрос, joins только к этой сущности.Это вполне возможно, но это также отдельный вопрос, и вам следует сначала попробовать сделать это самостоятельно.

Для полноты картины вы смоделировали отображение unidirectional ManyToMany, принадлежащее сущности This.

0 голосов
/ 17 июня 2019

Я не знаком с этой старой версией hibernate, но я бы попробовал заменить

    {@JoinColumn(name = "this_id")} by {@JoinColumn(name = "this.id")} 

и

    {@JoinColumn(name = "that_id")} by {@JoinColumn(name = "that.id")}
...