如何通過ResultTransformer和原生SQL或JPQL生成DTO?
獲取超出需要的資料更容易導致效能損失。使用DTO可以讓我們只提取所需的資料。在這個應用程式中,我們依賴於Hibernate ResultTransformer和原生SQL生成DTO?
對於不可變的DTO值物件和可變的DTO物件使用不同的方式,不可變的DTO值物件是final欄位,因此不能有setter欄位:
<b>public</b> <b>class</b> CarDtoNoSetters implements Serializable { <b>private</b> <b>static</b> <b>final</b> <b>long</b> serialVersionUID = 1L; <b>private</b> <b>final</b> String name; <b>private</b> <b>final</b> String color; <b>public</b> CarDtoNoSetters(String name, String color) { <b>this</b>.name = name; <b>this</b>.color = color; } <b>public</b> String getName() { <b>return</b> name; } <b>public</b> String getColor() { <b>return</b> color; } @Override <b>public</b> String toString() { <b>return</b> <font>"CarDtoNoSetters{"</font><font> + </font><font>"name="</font><font> + name + </font><font>", color="</font><font> + color + '}'; } } </font>
可變的DTO物件:
<b>public</b> <b>class</b> CarDtoWithSetters implements Serializable { <b>private</b> <b>static</b> <b>final</b> <b>long</b> serialVersionUID = 1L; <b>private</b> String name; <b>private</b> String color; <b>public</b> String getName() { <b>return</b> name; } <b>public</b> <b>void</b> setName(String name) { <b>this</b>.name = name; } <b>public</b> String getColor() { <b>return</b> color; } <b>public</b> <b>void</b> setColor(String color) { <b>this</b>.color = color; } @Override <b>public</b> String toString() { <b>return</b> <font>"CarDtoWithSetters{"</font><font> + </font><font>"name="</font><font> + name + </font><font>", color="</font><font> + color + '}'; } } </font>
編寫自己的DAO類,對於不可變的DTO值物件使用ResultTransformer+AliasToBeanConstructorResultTransformer,可變的使用ResultTransformer+Transformers.aliasToBean():
@Repository @Transactional <b>public</b> <b>class</b> Dao<T, ID <b>extends</b> Serializable> implements GenericDao<T, ID> { @PersistenceContext <b>private</b> EntityManager entityManager; @Transactional(readOnly = <b>true</b>) <b>public</b> List<CarDtoNoSetters> fetchCarsNoSetters() { Query query = entityManager .createNativeQuery(<font>"select name, color from car"</font><font>) .unwrap(org.hibernate.query.NativeQuery.<b>class</b>) .setResultTransformer( <b>new</b> AliasToBeanConstructorResultTransformer( CarDtoNoSetters.<b>class</b>.getConstructors()[0] ) ); List<CarDtoNoSetters> result = query.getResultList(); <b>return</b> result; } @Transactional(readOnly = <b>true</b>) <b>public</b> List<CarDtoWithSetters> fetchCarsWithSetters() { Query query = entityManager .createNativeQuery(</font><font>"select name, color from car"</font><font>) .unwrap(org.hibernate.query.NativeQuery.<b>class</b>) .setResultTransformer( Transformers.aliasToBean(CarDtoWithSetters.<b>class</b>) ); List<CarDtoWithSetters> result = query.getResultList(); <b>return</b> result; } <b>protected</b> EntityManager getEntityManager() { <b>return</b> entityManager; } } </font>
使用EntityManager.createNativeQuery()和unwrap(org.hibernate.query.NativeQuery.class)- 從Hibernate 5.2開始,ResultTransformer不推薦使用,但是直到可以使用替換(在Hibernate 6.0中)它可以使用(進一步閱讀 )
使用JPQL和原生SQL在SQL語句上稍微有點不同:
@Transactional(readOnly = <b>true</b>) <b>public</b> List<CarDtoNoSetters> fetchCarsNoSetters() { Query query = entityManager .createQuery(<font>"select c.name as name, c.color as color from Car c"</font><font>) .unwrap(org.hibernate.query.Query.<b>class</b>) .setResultTransformer( <b>new</b> AliasToBeanConstructorResultTransformer( CarDtoNoSetters.<b>class</b>.getConstructors()[0] ) ); List<CarDtoNoSetters> result = query.getResultList(); <b>return</b> result; } @Transactional(readOnly = <b>true</b>) <b>public</b> List<CarDtoWithSetters> fetchCarsWithSetters() { Query query = entityManager .createQuery(</font><font>"select c.name as name, c.color as color from Car c"</font><font>) .unwrap(org.hibernate.query.Query.<b>class</b>) .setResultTransformer( Transformers.aliasToBean(CarDtoWithSetters.<b>class</b>) ); List<CarDtoWithSetters> result = query.getResultList(); <b>return</b> result; } </font>