2017-01-17 3 views
11

Мне нужно применить SQL-запрос, подобный этому.Java Hibernate createSQLQuery с помощью addEntity

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.

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

+0

См. Ниже ответ, но самым простым способом было бы выбрать все столбцы из таблицы учеников (т. Е. Выбрать *). Тогда вы можете получить свою сущность. С точки зрения производительности выбор нескольких дополнительных столбцов редко бывает большим делом. – user2612030

ответ

8

В этом случае вы не хотите, чтобы спящий режим рассматривал Студент как сущность, а как 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. Я никогда не тестировал это на классе сущностей.

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

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

вместо этого.

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

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

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

Смежные вопросы