Hibernate SQL Результат запроса Отображение/преобразование объекта/класса/Bean
1 2: select (table. *)/(весь столбец) в порядке
String sql = "select t_student.* from t_student";
//String sql = "select t_student.id,t_student.name,... from t_student"; //select all column
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Student.class);//or query.addEntity("alias", Student.class);
//query.list();[[email protected], [email protected], [email protected]]
query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP); //or other transformer
query.list(); //[{Student(or alias)[email protected]},{[email protected]}]
3: выберите некоторый столбец (не все), это ошибка
String sql = "select t_student.id,t_student.name.t_student.sex from t_student";
SQLQuery query = session.createSQLQuery(sql);
query.addEntity(Student.class);
query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
query.list(); //Exception:invalid column/no column
Я хочу, чтобы "3" работало нормально, и пусть результат можно сопоставить с Student.class.
Например: Student [id =?, name=?, sex =?, (другое поле имеет значение null/default)]
Я не знаю этой ошибки, помогите мне!
Ответы
Ответ 1
Вы можете пойти дальше и добавить
.setResultTransformer(Transformers.aliasToBean(YOUR_DTO.class));
и автоматически сопоставить его с вашим пользовательским объектом dto, см. также Возврат не управляемых объектов.
Например:
public List<MessageExtDto> getMessagesForProfile2(Long userProfileId) {
Query query = getSession().createSQLQuery(" "
+ " select a.*, b.* "
+ " from messageVO AS a "
+ " INNER JOIN ( SELECT max(id) AS id, count(*) AS count FROM messageVO GROUP BY messageConversation_id) as b ON a.id = b.id "
+ " where a.id > 0 "
+ " ")
.addScalar("id", new LongType())
.addScalar("message", new StringType())
......... your mappings
.setResultTransformer(Transformers.aliasToBean(MessageExtDto.class));
List<MessageExtDto> list = query.list();
return list;
}
Ответ 2
Есть только два пути.
Вы можете использовать 1-й или 2-й фрагмент. Согласно документации Hibernate, вы должны предпочесть второй.
Вы можете получить список массивов объектов, например:
String sql = "select name, sex from t_student";
SQLQuery query = session.createSQLQuery(sql);
query.addScalar("name", StringType.INSTANCE);
query.addScalar("sex", StringType.INSTANCE);
query.list();
Ответ 3
Я хочу, чтобы "3" работало нормально, и пусть результат можно сопоставить с Student.class
Это возможно с помощью
Query createNativeQuery(String sqlString, String resultSetMapping
)
Во втором аргументе вы можете указать имя сопоставления результатов. Например:
1) Рассмотрим объект Студент, магия будет включена в аннотации SqlResultSetMapping:
import javax.persistence.Entity;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.Table;
@Entity
@Table(name = "student")
@SqlResultSetMapping(name = "STUDENT_MAPPING", classes = {@ConstructorResult(
targetClass = Student.class, columns = {
@ColumnResult(name = "name"),
@ColumnResult(name = "address")
})})
public class Student implements Serializable {
private String name;
private String address;
/* Constructor for the result mapping; the key is the order of the args*/
public Student(String aName, String anAddress) {
this.name = aName;
this.address = anAddress;
}
// the rest of the entity
}
2) Теперь вы можете выполнить запрос, результаты которого будут отображаться логикой STUDENT_MAPPING
:
String query = "SELECT s FROM student s";
String mapping = "STUDENT_MAPPING";
Query query = myEntityManager.createNativeQuery(query, mapping);
@SuppressWarnings("unchecked")
List<Student> students = query.getResultList();
for (Student s : students) {
s.getName(); // ...
}
Примечание. Я думаю, что избежать неконтролируемого предупреждения невозможно.
Ответ 4
У меня была такая же проблема с запросом HQL. Я решил проблему, изменив трансформатор.
Проблема вызвала преобразование кода в виде карты. Но он не подходит для Alias Bean. Вы можете увидеть код ошибки ниже. Код, написанный для передачи результата в виде карты и ввода нового поля на карту.
Класс: org.hibernate.property.access.internal.PropertyAccessMapImpl.SetterImpl
м
Метод: установите
@Override
@SuppressWarnings("unchecked")
public void set(Object target, Object value, SessionFactoryImplementor factory) {
( (Map) target ).put( propertyName, value );
}
Я решил проблему дублирования трансформатора и изменения кода.
Вы можете увидеть код в проекте.
Ссылка: https://github.com/robeio/robe/blob/DW1.0-migration/robe-hibernate/src/main/java/io/robe/hibernate/criteria/impl/hql/AliasToBeanResultTransformer.java
Класс:
import java.lang.reflect.Field;
import java.util.Map;
import io.robe.hibernate.criteria.api.query.SearchQuery;
import org.hibernate.HibernateException;
import org.hibernate.transform.AliasedTupleSubsetResultTransformer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AliasToBeanResultTransformer extends AliasedTupleSubsetResultTransformer {
private static final Logger LOGGER = LoggerFactory.getLogger(AliasToBeanResultTransformer.class);
private final Class resultClass;
// Holds fields of Transform Class as Map. Key is name of field.
private Map<String, Field> fieldMap;
public AliasToBeanResultTransformer(Class resultClass) {
if ( resultClass == null ) {
throw new IllegalArgumentException( "resultClass cannot be null" );
}
fieldMap = SearchQuery.CacheFields.getCachedFields(resultClass);
this.resultClass = resultClass;
}
@Override
public boolean isTransformedValueATupleElement(String[] aliases, int tupleLength) {
return false;
}
@Override
public Object transformTuple(Object[] tuple, String[] aliases) {
Object result;
try {
result = resultClass.newInstance();
for ( int i = 0; i < aliases.length; i++ ) {
String name = aliases[i];
Field field = fieldMap.get(name);
if(field == null) {
LOGGER.error(name + " field not found in " + resultClass.getName() + " class ! ");
continue;
}
field.set(result, tuple[i]);
}
}
catch ( InstantiationException e ) {
throw new HibernateException( "Could not instantiate resultclass: " + resultClass.getName() );
} catch ( IllegalAccessException e ) {
throw new HibernateException( "Could not instantiate resultclass: " + resultClass.getName() );
}
return result;
}
}
После создания нового трансформатора вы можете использовать, как показано ниже.
query.setResultTransformer(new AliasToBeanResultTransformer(YOUR_DTO.class));