DTO Projection: Hibernate expects a constructor although a resultTransformer ((AliasToBean)) is set


#1

Hi,
any idea what is wrong with my DTO Projection in the code below ?
I would like to select data with DTO Projection using the “Hibernate Criteria API”. Is it at all possible, or should i use JPQL,… ?

Hibernate expects a constructor with all the selected attributes although AliasToBeanResultTransformer is specified as transforming strategy (actually this way it should not be necessary to implement
any constructor with parameters). Or i have got it wrong ?
I don’t want to implement the expected constructor because my original query is a bit complex (with some joins,…) and it selects a lot of informations…

I would be highly grateful for your information

The error i get is :
“QuerySyntaxException: Unable to locate appropriate constructor on class MessageDetailsDTO… Expected arguments are: int, org.joda.time.DateTime [select new de.stroeer.core.message.dto.MessageListMessageDetailsDTO(generatedAlias0.id, generatedAlias0.creationTime)”

Here is my Code:

@Entity			
public class Message {
	public Message() {
	}
	
	@Id
	private long id;
	private DateTime creationTime;
	
	// getter and setter methods
}
			
public class MessageDetailsDTO {
	public MessageDetailsDTO() {
	}
	
	private long id;
	private DateTime creationTime;
	
	// getter and setter methods
}
CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<MessageDetailsDTO> criteriaQuery = builder.createQuery(MessageDetailsDTO.class);
Root<Message> root = criteriaQuery.from(Message.class);

criteriaQuery = 
	criteriaQuery.multiselect(root.get(Message_.id), root.get(Message_.creationTime))  //
		.where(root.get(MessageBean_.id).in(ids));

List<MessageDetailsDTO> result = 
		getEntityManager().createQuery(criteriaQuery)//
			.unwrap(org.hibernate.Query.class)
			.setResultTransformer(new AliasToBeanResultTransformer(MessageDetailsDTO.class))
			.list();

#2

That’s not even necessary because the Criteria API will be rendered to a JPQL which uses a Constructor Result as illustrated by the log message:

 select new de.stroeer.core.message.dto.MessageListMessageDetailsDTO(generatedAlias0.id, generatedAlias0.creationTime

Now, if you want to transform the Object[] using the AliasToBeanResultTransformer, you need to do it like this:

CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Object[]> criteriaQuery = builder.createQuery(Object[].class);
Root<Message> root = criteriaQuery.from(Message.class);

criteriaQuery = 
	criteriaQuery.multiselect(root.get(Message_.id), root.get(Message_.creationTime))  //
		.where(root.get(MessageBean_.id).in(ids));

List<MessageDetailsDTO> result = 
		getEntityManager().createQuery(criteriaQuery)//
			.unwrap(org.hibernate.Query.class)
			.setResultTransformer(new AliasToBeanResultTransformer(MessageDetailsDTO.class))
			.list();

#3

Hi Vlad

Thanks for the prompt answer.

I’ve already done it the same way you described above, but i still got the error

java.lang.ClassCastException: MessageDetailsDTO cannot be cast to java.util.Map

#4

I tested it as well and created HHH-13140 for this issue.


#5

Thanks a lot Vlad for your support.


#6

You’re welcome. I sent a fix. I hope it will be integrated in 5.4.