Как написать собственный @Query в Spring Data JDBC?

В примерах Spring Data JDBC, как мне написать простой запрос в аннотации @Query?

например Как мне добавить простой запрос findByName в Репозиторий LegoSet?

Когда я попробовал

@Query("select * from lego_set where name = :name") List<LegoSet> findByName(@Param("name") String name); он выдает следующую ошибку:

org.springframework.data.mapping.MappingException: Could not read property @org.springframework.data.annotation.Id() @org.springframework.data.relational.core.mapping.Column(value=handbuch_id, keyColumn=)private java.lang.Long example.springdata.jdbc.basics.aggregate.Manual.id from result set!
...

> Caused by: org.hsqldb.HsqlException: Column not found: manual_handbuch_idat org.hsqldb.error.Error.error(Unknown Source) at org.hsqldb.error.Error.error(Unknown Source) `

Кроме того, справочный документ, похоже, скопирован из некоторого общего документа с данными Spring, поскольку в нем упоминается производный запрос, который еще не существует в jdbc данных Spring.

Вероятно, вам нужно установить nativeQuery = true. Обратитесь к petrikainulainen.net/programming/spring-framework/…

user1211 25.10.2018 00:28

@ user1211 нет атрибута nativeQuery в аннотации Spring Data JDBCs @Query, поскольку все запросы должны предоставляться на собственном диалекте SQL используемой базы данных.

Jens Schauder 25.10.2018 07:23
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
4
2
6 724
3

Ответы 3

Объект LegoSet имеет отношение 1: 1 к Manual. Spring Data JDBC выбирает такую ​​конструкцию с помощью соединения и ожидает репрезентативные столбцы в ResultSet.

Обратите внимание, что он ожидает столбцы, представляющие сам объект Manual, плюс столбец, образующий обратную ссылку на LegoSet. Кроме того, все имена столбцов должны иметь префикс имени свойства + _, то есть в данном случае manual_.

Сообщение об ошибке фактически сообщает вам об отсутствующем столбце (по модулю отсутствующего пробела): Column not found: manual_handbuch_id.

В качестве альтернативы, вы также можете предоставить свой собственныйRowMapper

По поводу документации:

Вы в чем-то правы. Документация (почти) всех модулей Spring Data включает общую часть, которая легко приводит к путанице. Есть билет на поиск лучшего решения.

Из журнала я вижу, что собственный запрос для findAll () по умолчанию аналогичен тому, что вы упомянули, и я заменил свой запрос тем предложением plus where, которое сработало. Но не был уверен в соглашении об именах, таком как manual_handbuch_id. Также замечено от 1 до многих, это делается в отдельном запросе. Надеялся, что он тоже работает 1 на 1. Для более сложных случаев, когда у дочернего класса 1 на 1 есть собственный дочерний класс 1 на 1 и т. д., Тогда написание SQL будет нетривиальным и подверженным ошибкам.

Kevin Z 25.10.2018 17:32

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

Jens Schauder 25.10.2018 17:41

Насколько сложно во внутренней реализации относиться к 1 к 1 так же, как к 1 ко многим? Если это просто по соображениям производительности, по крайней мере, было бы неплохо предоставить это как вариант. Другой подход - предоставлять производные запросы как другие данные Spring, которые должны охватывать более 90% наших случаев. Я вспомнил, что вы упомянули, что он уже в пути на ваших семинарах? Надеюсь, скоро увидим. Спасибо.

Kevin Z 25.10.2018 17:59

Присоединение к 1: произойдет много. То же самое для вывода запросов. Я думал об упрощении написания пользовательских запросов.

Jens Schauder 25.10.2018 18:07

Думаю, я не совсем понимаю различия между Руководством и Моделью в этом примере. Они оба являются частью совокупности, почему в \ @Query я должен конкретно иметь дело с руководством, а не с моделью? В идеале мне не нужно беспокоиться о дочерних объектах в \ @Query.

Kevin Z 25.10.2018 21:45

Техническая причина заключается в том, что к совокупному корню можно присоединить любое количество взаимно однозначных отношений. Но с «один ко многим» в настоящее время ни одна из них не присоединяется (ожидается), поскольку, когда у вас более одной такой связи, вам нужно выбрать одну, к которой вы хотите присоединиться. В противном случае вы получите кросс-продукт с огромной мощностью.

Jens Schauder 26.10.2018 06:33

Поддерживает ли Spring data jdbc настраиваемые изменяемые запросы, например пользовательский запрос на вставку? Я получаю A result was returned when none was expected.

Tobi Akinyemi 16.10.2020 11:10

@TobiAkinyemi Да, это так: github.com/spring-projects/spring-data-jdbc/blob/…

Jens Schauder 16.10.2020 14:02

Я видел, как обновления работают нормально, но не вставки (возвращающие идентификатор). Это нормально работало с JPA

Tobi Akinyemi 16.10.2020 14:50

Вероятно, проблема в возврате идентификатора @TobiAkinyemi. Хотите создать проблему? jira.spring.io/browse/DATAJDBC

Jens Schauder 16.10.2020 16:19

@JensSchauder Просто чтобы уточнить, нельзя ли с помощью spring data jdbc выполнить эту вставку и получить идентификатор?

Tobi Akinyemi 16.10.2020 16:50

@TobiAkinyemi в настоящее время не поддерживает аннотацию запроса. Стандартное сохранение делает это. Или вы можете написать для него собственный метод.

Jens Schauder 16.10.2020 19:04

Позвольте нам продолжить обсуждение в чате.

Jens Schauder 16.10.2020 19:04

Я думаю, вы пытаетесь выполнить собственный запрос. Попробуйте, как показано ниже.

@Query(  value = "SELECT * FROM lego_set ls where ls.name = :name",
           nativeQuery = true)
  List<LegoSet> findByName(@Param("name") String name);

Это должно сработать.

Это относится к весенним данным jdbc, а не только к весенним данным jpa, поэтому nativeQuery не будет работать.

Kevin Z 25.10.2018 17:19

Так же, как завершение ответа @jens-schauder:

Запрос должен быть таким:

    @Query("SELECT ls.id, ls.name, ls.min_age, ls.max_age, " +
            "h.handbuch_id AS manual_handbuch_id, h.author AS manual_author, h.text AS manual_text " +
            "FROM lego_set ls JOIN handbuch h ON ls.id = h.handbuch_id " +
            "WHERE name = :name")
    List<LegoSet> findByName(@Param("name") String name);

Используя этот метод, проходят следующие тесты:

    @Test
    public void so_52978700() {
        // prepare
        LegoSet cars = createLegoSet("Small Car - 01", 5, 10);
        cars.setManual(new Manual("Just put all the pieces together in the right order", "Jens Schauder"));
        repository.save(cars);

        // execute
        List<LegoSet> actual = repository.findByName("Small Car - 01");

        // verify
        assertThat(actual).hasSize(1);
        assertThat(actual.get(0).getName()).isEqualTo("Small Car - 01");
        assertThat(actual.get(0).getManual().getText()).isEqualTo("Just put all the pieces together in the right order");
    }

Другие вопросы по теме