select firstName, lastName from Employee
query.setResultTransformer(Transformers.aliasToBean(MyResults.class));
You can't use above code with Hibernate 5 and Hibernate 4 (at least Hibernate 4.3.6.Final), because of an exception
java.lang.ClassCastException: com.github.fluent.hibernate.request.persistent.UserDto cannot be cast to java.util.Map
at org.hibernate.property.access.internal.PropertyAccessMapImpl$SetterImpl.set(PropertyAccessMapImpl.java:102)
The problem is that Hibernate converts aliases for column names to upper case — firstName
becomes FIRSTNAME
. And it tries to find a getter with name getFIRSTNAME()
, and setter setFIRSTNAME()
in the DTO
using such strategies
PropertyAccessStrategyChainedImpl propertyAccessStrategy = new PropertyAccessStrategyChainedImpl(
PropertyAccessStrategyBasicImpl.INSTANCE,
PropertyAccessStrategyFieldImpl.INSTANCE,
PropertyAccessStrategyMapImpl.INSTANCE
);
Only PropertyAccessStrategyMapImpl.INSTANCE
suits, in opinion of Hibernate, well. So after that, it tries to do conversion (Map)MyResults
.
public void set(Object target, Object value, SessionFactoryImplementor factory) {
( (Map) target ).put( propertyName, value );
}
Don't know, it is a bug or feature.
How to solve
Using aliases with quotes
public class Results {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
String sql = "select firstName as \"firstName\",
lastName as \"lastName\" from Employee";
List<Results> employees = session.createSQLQuery(sql).setResultTransformer(
Transformers.aliasToBean(Results.class)).list();
Using a custom result transformer
Another way to solve the problem — using a result transformer that ignores method names case (treat getFirstName()
as getFIRSTNAME()
). You can write your own or use FluentHibernateResultTransformer. You will not need to use quotes and aliases (if you have column names equal to DTO names).
Just download the library from the project page (it doesn't need additional jars): fluent-hibernate.
String sql = "select firstName, lastName from Employee";
List<Results> employees = session.createSQLQuery(sql)
.setResultTransformer(new FluentHibernateResultTransformer(Results.class))
.list();
This transformer can be used for nested projections too: How to transform a flat result set using Hibernate