SpringBoot 3 (данные) ключевое слово isTrue не работает

Я вижу что-то странное после обновления своего приложения до SpringBoot 3 с SpringBoot 2.

Приложение использует существующую базу данных (MySQL), которая не использует передовой опыт. Один из них использует YN для логических значений, хранящихся в VARCHAR.

Чтобы упростить работу с Java, я создал конвертер, который выглядит так:

@Converter
public class BooleanToStringConverter implements AttributeConverter<Boolean, String> {

    @Override
    public String convertToDatabaseColumn(Boolean attribute) {
        if (attribute == null) {
            return null;
        }
        return attribute ? "Y" : "N";
    }

    @Override
    public Boolean convertToEntityAttribute(String dbData) {
        if (dbData == null) {
            return null;
        }
        return dbData.equals("Y");
    }
}

И на своих бобах я использую его как:

@Column(name = "DELIVERED")
@Convert(converter = BooleanToStringConverter.class)
private Boolean delivered;

Все идет нормально.

Если я создам репозиторий для запроса всех доставленных объектов, я напишу что-то вроде этого в SpringBoot 2:

List<MyClass> findAllByDeliveredIsTrue();

Но если я запускаю это в SpringBoot 3, он возвращает пустой список.

Мне нужно написать запрос вручную, чтобы он работал.

@Query("SELECT c FROM MyClass c WHERE c.delivered = true")
List<MyClass> findAllByDeliveredIsTrue();

Есть идеи, почему это происходит?


Редактировать:

Я включил журналы SQL, и определенно запросы создаются по-другому. Для простоты я перевел некоторые вещи в посте, потому что в реальном сценарии база данных на испанском языке и использует S/N вместо Y/N.

Java service
    @PostConstruct
    public void init() {
        log.error("DEBUG INIT");
        repo.findFirstByActiuIsTrueOrderByDataDesc();
        repo.findFirstByActiuIsTrueOrderByDataDesc1(); ///Working case
        log.error("DEBUG END");
    }

Repository

//Failing case
Optional<Condicio> findFirstByActiuIsTrueOrderByDataDesc();


@Query("SELECT c FROM Condicio c WHERE c.actiu = true ORDER BY c.data ASC")
Optional<Condicio> findFirstByActiuIsTrueOrderByDataDesc1(); //Working case

2023-05-13T10:23:19.336+02:00 ERROR 42936 --- [  restartedMain] c.n.a.backend.service.CondicioService    : DEBUG INIT
Hibernate: select c1_0.COND_CONDICIO,c1_0.COND_ACTIU,c1_0.COND_DATA,c1_0.COND_DESCRIPCIO from CONDICIONS c1_0 where c1_0.COND_ACTIU order by c1_0.COND_DATA desc limit ?
Hibernate: select c1_0.COND_CONDICIO,c1_0.COND_ACTIU,c1_0.COND_DATA,c1_0.COND_DESCRIPCIO from CONDICIONS c1_0 where c1_0.COND_ACTIU='S' order by c1_0.COND_DATA asc
2023-05-13T10:23:19.451+02:00 ERROR 42936 --- [  restartedMain] c.n.a.backend.service.CondicioService    : DEBUG END

Вы уверены, что Spring Boot автоматически настраивает репозиторий как репозиторий JPA? Действительно ли тот же код работал в Spring Boot 2? Видите ли вы в журналах: «Загрузка репозиториев Spring Data JPA» и «Найдены интерфейсы репозитория NNN JPA»

Mar-Z 12.05.2023 12:39

Если «SELECT c FROM MyClass c WHERE c.delivered = true» работает, не означает ли это, что DELIVERED на самом деле является BOOLEAN, а не VARCHAR?

k314159 12.05.2023 12:46

Тот же код работает в SB 2. JPA настроен правильно, и я вижу упомянутый журнал. Кроме того, сработает переписывание запроса как findAllByDelivered(Boolean delivered);. Как уже упоминалось, на уровне базы данных базовым типом является VARCHAR, и используется преобразователь.

Alex Roig 13.05.2023 10:19

@AlexRoig ты пробовал не использовать глагол is? то есть findAllByDeliveredTrue вместо findAllByDeliveredIsTrue?

Andrey B. Panfilov 15.05.2023 11:03

@AndreyB.Panfilov Пожалуйста, укажите, как именно изменение имени метода, как вы предлагаете, может решить эту проблему. Это невозможно.

user207421 15.05.2023 11:45

@OP В вашем посте нет ключевого слова isTrue. Просьба уточнить.

user207421 15.05.2023 11:46

@ user207421 Я бы посоветовал сначала прочитать официальную документацию: «True findByActiveTrue () … где x.active = true»

Andrey B. Panfilov 15.05.2023 11:51

Вы тщательно обрабатываете «ноль» как третье возможное значение. Возможно, проблема в нем?

Rick James 15.05.2023 18:50
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
5
8
170
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Код, который вы показали, работает не с логическим значением, а со значением с тремя состояниями. Решите, что вы будете делать с NULL. Тогда убедитесь, что в вашем коде есть 3 случая.

Я бы не стал пытаться исправить да/нет в VARCHAR, если вы действительно не можете исправить схему и данные. Вместо этого проверяйте == 'N' по мере необходимости. (Я выбрал сторону «нет», потому что это работает с большинством европейских языков.

Однако обратите внимание, что == 'Y' — это не то же самое, что != 'N' — из-за опции NULL.

Кроме того, убедитесь, что COLLATION этого VARCHAR складывается по регистру, так что 'n' == 'N'. Имя сопоставления должно заканчиваться на `_ci``.

Обработка нулей — хороший момент, но реализация преобразователя BooleanToString, которую я уже рассмотрел, уже охватывает это. Дело в том, что эти запросы работали на SpringBoot 2 и ни с того ни с сего на Spring Boot 3 они больше не работают. Похоже, что есть какой-то новый оптимизатор запросов, который заменяет JPQL на c1_0.COND_ACTIU для неявной проверки логического истинного состояния вместо его указания, и, поскольку он не проходит через преобразователь, БД фактически не знает, с чем его сравнивать. БД — это то, что я не могу изменить, и есть собственная ERP, и мы не можем ее контролировать.

Alex Roig 15.05.2023 21:50
Ответ принят как подходящий

Оказывается, это проблема CriteriaBuilder в Spring Data. Проблема отслеживается в выпуске репозитория № 2800. На момент ответа он все еще не решен, и затронутые версии по крайней мере Spring Boot 3.0.2

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