Java Hibernate createSQLQuery с помощью addEntity

Мне нужно применить SQL-запрос, похожий на это.

SELECT
    id as id,
    c03 as c03,
    c34 as c34 
FROM
    (SELECT
        id,
        c03,
        c34 
    FROM
        students
    where
        c34 in(
            ?, ?,?,?
        ) 
    order by
        id desc) o 
group by
    c34;

И мой код Java.

private final void retrieveStudents(){
    final List result = currentSession()
            .createSQLQuery("SELECT id as id,c03 as c03,c34 as c34 FROM (SELECT id,c34,c03 FROM students where c34 in(:filters) order by id desc) o group by c34;")
            .setParameterList("filters",Arrays.asList(74,1812))
            .list();
    result.forEach(this::consumer1);
}

Запрос просто ОК. Возвращает массив объектов, которые я могу выполнять, но я хотел бы вернуть объект Student, поэтому я добавляю.

   .addEntity(Student.class)

Но ошибка - это бросок, в котором говорится

Column 'ACTIVE' not found.

Также я попытался с .addScalar, но происходит то же самое.

.addScalar("id",org.hibernate.type.IntegerType.INSTANCE)
.addScalar("c03",org.hibernate.type.DateType.INSTANCE)

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

Все, что я хочу, это объект-ученик с заселенными значениями id, c03, c34.

Что я делаю неправильно, возможно?

Ответ 1

В этом случае вы не хотите, чтобы спящий режим рассматривал Студент как объект, а как DTO.

Для этого не используйте метод addEntity, но setResultTransfomer:

final List result = currentSession()
        .createSQLQuery("SELECT id as id,c03 as c03,c34 as c34 " + 
                         "FROM (SELECT id,c34,c03 FROM students " + 
                               "where c34 in(:filters) " + 
                               "order by id desc) o group by c34")
        .setParameterList("filters",Arrays.asList(74,1812))
        .addScalar("id",org.hibernate.type.IntegerType.INSTANCE)
        .addScalar("c03",org.hibernate.type.DateType.INSTANCE)
        .addScalar("c34",org.hibernate.type.DateType.INSTANCE)
        .setResultTransformer(Transformers.aliasToBean(Student.class))
        .list();

Это работает для классов без сущностей, если у класса есть сеттеры, которые соответствуют именам проецируемых столбцов, и есть конструктор no-arg. Я никогда не тестировал это в классе сущностей.

Если у вас нет сеттеров, но конструктор для этих трех полей, вы можете использовать:

// choose here the right constructor
java.lang.reflect.Constructor constructor = Student.class.getConstructors()...
// ...
.setResultTransformer(new AliasToBeanConstructorResultTransformer(constructor));

вместо.

ИЗМЕНИТЬ: Я бы не использовал объект как DTO (но создавал конкретный DTO для этого варианта использования): что, если один из ваших сервисов подумает, что объект загружен обычным способом (так что он полностью инициализирован), внесите некоторые изменения (обновите например, поле) и сохранить объект?

В лучшем случае неэлементное поле (на стороне db) не будет инициализировано, и вы получите исключение ConstraintViolationException и инициируете откат, сохраняя ваши данные в безопасности.

В худшем случае вы будете искажать свои данные, установив null все поля объекта, но три загруженные.