You are on page 1of 5

In Relation To... Hibernate 3.

2: Transformers for HQL and SQL

http://relation.to/2133.lace

Username:

Password (Reset): Login Members Browse

Bloggers Max Hibernate 3.2: Transformers for HQ...

Bloggers
Gavin Ales Aslak Christian Dan Daniel David Emmanuel Gail Hardy Ilya Jason Jason P Jay Jesper Jozef Lincoln Marek Max Nicklas Norman Pete Sanne Scott Shane Steve Strong Liu Stuart Tihomir Search... Find

Hibernate 3.2: Transformers for HQL and SQL


People using the Criteria API have either transparently or knowingly used a ResultTransformer . A ResultTransformer is a nice and simple interface that allows you to transform any Criteria result element. E.g. you can make any Criteria result be returned as a java.util.Map or as a non-entity Bean.

Criteria Transformers
Imagine you have a StudentDTO class:
public class StudentDTO { private String studentName; private String courseDescription; public StudentDTO() { } ... }

Then you can make the Criteria return non-entity classes instead of scalars or entities by applying a ResultTransformer:
List resultWithAliasedBean = s.createCriteria(Enrolment.class) .createAlias("student", "st").createAlias("course", "co") .setProjection( Projections.projectionList() .add( Projections.property("st.name"), "studentName" ) .add( Projections.property("co.description"), "courseDescription" ) .setResultTransformer( Transformers.aliasToBean(StudentDTO.class) ) .list(); StudentDTO dto = (StudentDTO)resultWithAliasedBean.get(0);

This is how ResultTransformer have been available since we introduced projection to the Criteria API in Hibernate 3. It is just one example of the built in transformers and users can provide their own transformers if they so please.

Jealous programming
Since I am more a HQL/SQL guy I have been jealous on Criteria for having this feature and I have seen many requests for adding it to all our query facilities. Today I put an end to this jealousy and introduced ResultTransformer for HQL and SQL in Hibernate 3.2.

HQL Transformers
In HQL we already had a kind of result transformers via the (select new

1 of 5

Friday 17 February 2012 04:17 PM

In Relation To... Hibernate 3.2: Transformers for HQL and SQL

http://relation.to/2133.lace

Bloggers
Gavin Ales Aslak Christian Dan Daniel David Emmanuel Gail Hardy Ilya Jason Jason P Jay Jesper Jozef Lincoln Marek Max Nicklas Norman Pete Sanne Scott Shane Steve Strong Liu Stuart Tihomir Find

http://www.hibernate.org/hib_docs/v3/reference/en/html/queryhql.html#queryhql-select) syntax, but for returning non-entity beans it only provided value injection of these beans via its constructor. Thus if you used the same DTO in many different scenarios you could end up having many constructors on this DTO purely for allowing the select new functionality to work. Now you can get the value injected via property methods or fields instead, removing the need for explicit constructors.
List resultWithAliasedBean = s.createQuery( "select e.student.name as studentName," + " e.course.description as courseDescription" + "from Enrolment as e") .setResultTransformer( Transformers.aliasToBean(StudentDTO.class)) .list(); StudentDTO dto = (StudentDTO) resultWithAliasedBean.get(0);

SQL Transformers
With native sql returning non-entity beans or Map's is often more useful instead of basic Object[]. With result transformers that is now possible.
List resultWithAliasedBean = s.createSQLQuery( "SELECT st.name as studentName, co.description as courseDescription " + "FROM Enrolment e " + "INNER JOIN Student st on e.studentId=st.studentId " + "INNER JOIN Course co on e.courseCode=co.courseCode") .addScalar("studentName") .addScalar("courseDescription") .setResultTransformer( Transformers.aliasToBean(StudentDTO.class)) .list(); StudentDTO dto =(StudentDTO) resultWithAliasedBean.get(0);

Tip: the addScalar() calls were required on HSQLDB to make it match a property name since it returns column names in all uppercase (e.g. STUDENTNAME). This could also be solved with a custom transformer that search the property names instead of using exact match - maybe we should provide a fuzzyAliasToBean() method ;)

Map vs. Object[]


Since you can also use a transformer that return a Map from alias to value/entity (e.g. Transformers.ALIASTOMAP), you are no longer required to mess with index based Object arrays when working with a result.
List iter = s.createQuery( "select e.student.name as studentName," + " e.course.description as courseDescription" + "from Enrolment as e") .setResultTransformer( Transformers.ALIAS_TO_MAP ) .iterate(); String name = (Map)(iter.next()).get("studentName");

Again, this works equally well for Criteria, HQL and native SQL.

Reaching Nirvana of native sql

2 of 5

Friday 17 February 2012 04:17 PM

In Relation To... Hibernate 3.2: Transformers for HQL and SQL

http://relation.to/2133.lace

Bloggers
Gavin Ales Aslak Christian Dan Daniel David Emmanuel Gail Hardy Ilya Jason Jason P Jay Jesper Jozef Lincoln Marek Max Nicklas Norman Pete Sanne Scott Shane Steve Strong Liu Stuart Tihomir

We still miss a few things, but with the addition of ResultTranformer support for SQL and the other additions lately to the native sql functionality in Hibernate we are close to reach the Nirvana of native sql support. Combined with StatelessSession you actually now got a very flexible and full powered sql executor which transparently can map to and from objects with native sql without any ORM overhead. ...and when you get tired of managing the sql, objectstate, lifecycles, caching etc. of your objects manually and want to benefit from the power of an ORM then you got it all readily available to you ;)

Created: 17. Mar 2006, 16:56 CET (Max Andersen) Last Modified: 03. Jun 2008, 21:49 CET (Christian Bauer)

10 comments:
18. Apr 2006, 20:47 CET | Link Joel

I always thought that the result transformers were provided to Criteria to give it the functionality you could get from using HQL with the "new" syntax. "select new com.CustomerDTO(ent.id, ent.name) from com.CustomerEntity ent" I haven't gotten to look at the result transformers myself, they must be more powerful than the simple use case I have.
Reply Quote

19. Apr 2006, 01:10 CET | Link Max Rydahl Andersen | max(AT)hibernate.org

yes, you are mostly correct.


Find

select new is equal to some of the transformations you can do, but we don't have a way to do "setter injection" via "select new" and it did not work for sql queries. It does now.
Reply Quote

03. Nov 2006, 00:34 CET | Link Cablo

Transformer injection is perfect, but not works with compound entities. For example: entity has primary key class (properties p1, p2) with name "id" and I want to set these properties via alias "id.p1" and "id.p2". Transformer fails, because it not find bean property with name "id.p1"

3 of 5

Friday 17 February 2012 04:17 PM

In Relation To... Hibernate 3.2: Transformers for HQL and SQL

http://relation.to/2133.lace

Bloggers
Gavin Ales Aslak Christian Dan Daniel David Emmanuel Gail Hardy Ilya Jason Jason P Jay Jesper Jozef Lincoln Marek Max Nicklas Norman Pete Sanne Scott Shane Steve Strong Liu Stuart Tihomir Find

10 comments: in base entity.


Problem is, that Transformer doesn't use "deep property search". Is it mistake??? Thank, Charles

Reply

Quote

22. Oct 2008, 13:00 CET | Link krishna | krishna81m(AT)gmail.com

This is a important addition especially to solve performance issues while being able to write efficient dynamic HQL queries. But, how do we modify the HQL transformer in case of loading a specific parent or another mapped entity property. session.createQuery( "select st.stNumber as stNumber, st.stDate as stDate " + " from SomeTable st " + " where st.someTableId < 1000") .setResultTransformer( Transformers.aliasToBean(database.SomeTable.class)) .list(); works fine but what if I want to load some of its parents properties only, as lets say, SomeTable has a parent called SomedParent and I want to access one of the fields of this parent only session.createQuery( "select st.stNumber as stNumber, st.stDate as stDate, st.someParent.someParentField as someParentField " + " from SomeTable st " + " where st.someTableId < 1000") .setResultTransformer( Transformers.aliasToBean(database.SomeTable.class)) .list(); This fails, so any ideas?
Reply Quote

20. Mar 2009, 22:44 CET | Link Tom

some basics information about ht: http://hibernatetutorial.com/Hibernate-tutorial-SQL-in-hibernate.html


Reply Quote

4 of 5

Friday 17 February 2012 04:17 PM

In Relation To... Hibernate 3.2: Transformers for HQL and SQL

http://relation.to/2133.lace

10 comments: Bloggers
Gavin Ales Aslak Christian Dan Daniel David Emmanuel Gail Hardy Ilya Jason Jason P Jay Jesper Jozef Lincoln Marek Max Nicklas Norman Pete Sanne Scott Shane Steve Strong Liu Stuart Tihomir Find Reply Quote 30. Sep 2010, 20:04 CET | Link Rmulo | romulomail(AT)gmail.com Reply Quote 29. May 2009, 07:59 CET | Link Jared OduLio

Just a few question on the sample code. How did you able to cast Map to a String variable name? Does iterate() really returns a List?
Reply Quote

03. Dec 2009, 23:51 CET | Link Steve Cohen

addScalar() throws UnsupportedOperationException (in AbstractList.add()) when applied to a SQL query created by Session.getNamedQuery(). There seems to be a different path toward creating the scalar list on a Named Query. I think this is a bug. There may be a workaround, but I didn't have time to work it out. I punted used createSQLQuery(). Has anyone else encountered this and if so, how is it solved?

26. Dec 2009, 17:49 CET | Link Parthiv

Thanks. your article has helped us a lot.. Neatly Described.. good job..
Reply Quote

Can the ResultTransformer accpet a class that doesn't have a private constructor with no arguments?

30. Sep 2010, 20:05 CET | Link Rmulo | romulomail(AT)gmail.com

Rmulo wrote on Sep 30, 2010 14:04: Can the ResultTransformer accpet a class that doesn't have a private constructor with no arguments? I mean doesn't have a PUBLIC constructor.
Reply Quote

Post Comment

This website was created with JBoss Seam and runs on JBoss Application Server.

5 of 5

Friday 17 February 2012 04:17 PM

You might also like