JPA — Attributeconverter не работает с собственным запросом

#sql #spring-boot #hibernate #spring-data-jpa

#sql #весенняя загрузка #спящий режим #spring-data-jpa

Вопрос:

Я создал класс AttributeConverter, который преобразует Enum в значение DB и переопределяет необходимые методы. Если я использую JPA-запрос, как показано ниже, вызывается конвертер и получает правильный результат.

 public List<Driver> findByStatus(DriverStatus status);
    
  

НО если я использую с аннотацией запроса, этот AttributeConverter не вызывается. У меня есть более сложный запрос, в котором мне нужно использовать собственный запрос с преобразователем атрибутов, но у меня это не работает.

 @Query(value = "select * from driver where status=:status", nativeQuery = true)
    public List<Driver> findByStatus1(DriverStatus status);
  

есть ли какой-либо способ выполнить это требование?

Обновление 1 — ниже приведен код конвертера

 @Converter(autoApply = true)
public class DriverStatusConverter implements AttributeConverter<DriverStatus, String> {

    @Override
    public String convertToDatabaseColumn(DriverStatus driverStatus) {
        if (driverStatus == null) {
            return null;
        }
        System.err.println("from converter"  driverStatus.getCode());
        return driverStatus.getCode();
    }

    @Override
    public DriverStatus convertToEntityAttribute(String code) {

        if (code == null) {
            return null;
        }

        return Stream.of(DriverStatus.values()).filter(c -> c.getCode().equals(code)).findFirst()
                .orElseThrow(IllegalArgumentException::new);
    }
}
  

Комментарии:

1. Если возможно, не могли бы вы converter entity также предоставить фрагмент кода and ?

2. добавлен код для вопроса @Sujitmohanty30

3. спасибо, но я также хотел бы, чтобы вы также добавили объект.

Ответ №1:

Столкнулся с подобной проблемой, не смог найти удовлетворительного решения, поэтому пришлось прибегнуть к уродливому взлому… Подпись метода репозитория была изменена следующим образом:

 public List<Driver> findByStatus1(Integer status);
  

…и вызывался так:

 repository.findByStatus1(DriverStatus.YOUR_DESIRED_STATUS.getCode());
  

Да, это некрасиво и отчасти противоречит цели AttributeConverter, но, по крайней мере, это работает. В моем конкретном случае мне пришлось прибегнуть к таким мерам только с одним собственным запросом. AttributeConverter по-прежнему работает для всех других запросов JPA.

Ответ №2:

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

DriverStatusConverter переместить логический код в convertToEntityAttribute общедоступный статический метод:

 @Override
public DriverStatus convertToEntityAttribute(String code) {

    return convertStringToEnum(code);
}

public static DriverStatus convertStringToEnum(String code) {
    if (code == null) {
        return null;
    }

    return Stream.of(DriverStatus.values()).filter(c -> c.getCode().equals(code)).findFirst()
                .orElseThrow(IllegalArgumentException::new);
}
  

создать новый DriverDTO для результата собственного запроса

 public interface DriverDTO {
    
    public Integer getId();

    public String getName();
    
    public String getStatusCode();

    default DriverStatus getStatus() {
        return DriverStatusConverter.convertStringToEnum(getStatusCode());
    }

}
  

DriverRepository findByStatusCode() выбирает столбцы в запросе и возвращает DriverDTO класс

 @Query(value = "select id, name, status as statusCode from driver WHERE status=:statusCode", nativeQuery = true)
public List<DriverDTO> findByStatusCode(String statusCode);
  

Ответ №3:

Удалите nativeQuery = true и попробуйте.

 @Query(value = "select * from driver where status=:status")
    public List<Driver> findByStatus1(DriverStatus status);
  

В качестве альтернативы вы можете попробовать использовать entityManager вот так —
Это всего лишь пример кода.

 TypedQuery<Trip> q = entityManager.createQuery("SELECT t FROM Trip t WHERE t.vehicle = :v", Trip.class);
q.setParameter("v", Vehicle.PLANE);
List<Trip> trips = q.getResultList();
  

Ссылка —
https://thorben-janssen.com/jpa-21-type-converter-better-way-to /

Комментарии:

1. Предлагаемый запрос недопустим JPQL

2. Вы говорите о втором? Это был всего лишь пример того, как вы можете использовать entityManager для создания запроса. Я уже упоминал в ответе, что это был всего лишь образец. По сути, идея в том, что я хотел, чтобы вы попробовали использовать entityManager .

3. Я говорю о первом

4. Как это неправильно? Вот ссылка: baeldung.com/spring-data-jpa-query

5. select * from driver where status=:status является собственным SQL-запросом. Вы не можете просто удалить nativeQuery = true и ожидать, что это сработает. В ссылке, на которую вы ссылаетесь, запросы для nativeQuery = true и nativeQuery = false отличаются