#java #hibernate #jpa #spring-data-jpa #jpql
Вопрос:
В настоящее время я борюсь с пользовательским запросом JPQL, который должен быть простым, по крайней мере, на первый взгляд.
Стек: Java 11, spring-boot 2.4.5, spring-boot-starter-данные-jpa 2.4.8, ядро гибернации 5.4.16, база данных Postgre.
дело
Мне просто нужен мой запрос JPQL для извлечения 3 полей, исходящих от родительской сущности, и это дочерняя/вложенная сущность (сопоставленная как однонаправленная связь один к одному), в пользовательском DTO, а не сущность из домена.
Домен выглядит так:
@Entity
@Table(name = "Item")
public class ItemEntity {
@Id
private Long id;
@NotNull
private String field1;
@ManyToOne
@JoinColumn(name = "nestedEntity_id", referencedColumnName = "id")
private NestedEntity nestedEntity;
//...
}
@Entity
@Table(name = "Nested")
public class NestedEntity {
@Id
private Long id;
@NotNull
private String field1;
@NotNull
private String field2;
//...
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class MyDTO {
@NotNull
private String myField;
private String concatedNestedFields;
private String otherNestedField;
//...
}
Я думал, что это легко, и сделал что-то вроде этого:
@Query("SELECT new my.package.MyDto(itemEntity.field1, CONCAT(itemEntity.nestedEntity.field1, ' ', itemEntity.nestedEntity.field2), itemEntity.nestedEntity.field3) FROM ItemEntity itemEntity WHERE itemEntity.country = :country")
MyDTO findByCountry(@Param("country") CountryEnum country);
ОСОБЕННОСТИ
Я не знаю, имеет ли это отношение к делу или нет, но поля вложенных сущностей @NotNull
аннотированы.
проблема
Проблема возникает, когда значение nestedEntity равно нулю: запрос ничего не возвращает, несмотря на то, что элемент «родительский» существует. Если значение nestedEntity не равно нулю, запрос работает.
ЧТО Я ПЫТАЛСЯ
Я попытался использовать функцию COALESCE (), которая возвращает первое ненулевое значение из приведенных нами параметров для каждого поля вложенности, как показано ниже:
@Query("SELECT new my.package.MyDto(itemEntity.field1, COALESCE(CONCAT(itemEntity.nestedEntity.field1, ' ', itemEntity.nestedEntity.field2),'-'), COALESCE(itemEntity.nestedEntity.field3), '-') FROM ItemEntity itemEntity WHERE itemEntity.country = :country")
MyDTO findByCountry(@Param("country") CountryEnum country);
Но это тоже не работает.
ОБНОВЛЕНИЕ Я только что попробовал что-то, чтобы устранить некоторые коренные причины. Если я выполняю именованный запрос JPA, предоставленный spring-data / JPA, и возвращаю сущность вместо моего пользовательского DTO, он работает даже с вложенной сущностью null. Он извлекает сущность с вложенной нулевой сущностью. Запрос выглядит так:
ItemEntity findItemEntityByCountry(@Param("country") CountryEnum country);
Я не уверен, какой вывод можно сделать по этому поводу, но это может помочь тем, кто понимает JPA лучше, чем я (а это многие люди… XD).
Я не нашел никаких онлайн-ресурсов по этому делу, и я немного заблудился.
Я был бы очень признателен, если бы вы, ребята, помогли мне с этим маленьким удивительно сложным запросом!
Большое спасибо за ваше время, ребята! Надеюсь, это тоже поможет другим 🙂
Комментарии:
1. Ваша проблема в
.
том, что оператор навигации i. e. имеет внутреннюю семантику соединения в соответствии со спецификацией JPA, поэтому, если связь равна нулю, из — за этого отфильтровывается вся строка. Чтобы решить эту проблему, вам нужно присоединиться к ассоциации слева и использовать псевдоним соединения вместо полного пути при передаче выражения конструктора.
Ответ №1:
попробуйте выполнить следующее левое соединение
@Query("SELECT new my.package.MyDto(itemEntity.field1,
CONCAT(nestedEntity.field1, ' ', nestedEntity.field2),
nestedEntity.field3)
FROM ItemEntity itemEntity left join itemEntity.nestedEntity as nestedEntity
WHERE itemEntity.country = :country")
MyDTO findByCountry(@Param("country") CountryEnum country);
в противном случае не используйте concat, а просто передайте nestedEntity.поле 2 и выполните объединение на стороне java
Комментарии:
1. Спасибо за ответ, но, к сожалению, это не работает для меня. У меня все еще есть пустой возврат, с использованием или без использования функции CONCAT…