如何透過ResultTransformer和原生SQL或JPQL生成DTO?

banq發表於2019-02-13

獲取超出需要的資料更容易導致效能損失。使用DTO可以讓我們只提取所需的資料。在這個應用程式中,我們依賴於Hibernate ResultTransformer和原生SQL生成DTO?

對於不可變的DTO值物件和可變的DTO物件使用不同的方式,不可變的DTO值物件是final欄位,因此不能有setter欄位:


public class CarDtoNoSetters implements Serializable {

    private static final long serialVersionUID = 1L;

    private final String name;
    private final String color;       

    public CarDtoNoSetters(String name, String color) {
        this.name = name;
        this.color = color;
    }

    public String getName() {
        return name;
    }

    public String getColor() {
        return color;
    }            

    @Override
    public String toString() {
        return "CarDtoNoSetters{" + "name=" + name + ", color=" + color + '}';
    }           
}

可變的DTO物件:


public class CarDtoWithSetters implements Serializable {

    private static final long serialVersionUID = 1L;
    
    private String name;
    private String color;    

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }          

    @Override
    public String toString() {
        return "CarDtoWithSetters{" + "name=" + name + ", color=" + color + '}';
    }        
}


編寫自己的DAO類,對於不可變的DTO值物件使用ResultTransformer+AliasToBeanConstructorResultTransformer,可變的使用ResultTransformer+Transformers.aliasToBean():


@Repository
@Transactional
public class Dao<T, ID extends Serializable> implements GenericDao<T, ID> {
    
    @PersistenceContext
    private EntityManager entityManager;

    
    @Transactional(readOnly = true)
    public List<CarDtoNoSetters> fetchCarsNoSetters() {
        Query query = entityManager
                .createNativeQuery("select name, color from car")
                .unwrap(org.hibernate.query.NativeQuery.class)
                .setResultTransformer(
                        new AliasToBeanConstructorResultTransformer(
                                CarDtoNoSetters.class.getConstructors()[0]
                        )
                );
        
        List<CarDtoNoSetters> result = query.getResultList();
        
        return result;
    }
    
    @Transactional(readOnly = true)
    public List<CarDtoWithSetters> fetchCarsWithSetters() {
        Query query = entityManager
                .createNativeQuery("select name, color from car")
                .unwrap(org.hibernate.query.NativeQuery.class)
                .setResultTransformer(
                        Transformers.aliasToBean(CarDtoWithSetters.class)
                );        

        List<CarDtoWithSetters> result = query.getResultList();
        
        return result;
    }    
    
    protected EntityManager getEntityManager() {
        return entityManager;
    }
}



使用EntityManager.createNativeQuery()和unwrap(org.hibernate.query.NativeQuery.class)- 從Hibernate 5.2開始,ResultTransformer不推薦使用,但是直到可以使用替換(在Hibernate 6.0中)它可以使用(進一步閱讀

使用JPQL和原生SQL在SQL語句上稍微有點不同:

   @Transactional(readOnly = true)
    public List<CarDtoNoSetters> fetchCarsNoSetters() {
        Query query = entityManager
                .createQuery("select c.name as name, c.color as color from Car c")
                .unwrap(org.hibernate.query.Query.class)
                .setResultTransformer(
                        new AliasToBeanConstructorResultTransformer(
                                CarDtoNoSetters.class.getConstructors()[0]
                        )
                );
        
        List<CarDtoNoSetters> result = query.getResultList();
        
        return result;
    }
    
    @Transactional(readOnly = true)
    public List<CarDtoWithSetters> fetchCarsWithSetters() {
        Query query = entityManager
                .createQuery("select c.name as name, c.color as color from Car c")
                .unwrap(org.hibernate.query.Query.class)
                .setResultTransformer(
                        Transformers.aliasToBean(CarDtoWithSetters.class)
                );        

        List<CarDtoWithSetters> result = query.getResultList();
        
        return result;
    }    



原生SQL

JPQL原始碼

 

相關文章