使用addEntity

时间:2017-01-17 11:03:31

标签: java hibernate

我需要应用与此类似的SQL查询。

SELECT
    id as id,
    c03 as c03,
    c34 as c34 
FROM
    (SELECT
        id,
        c03,
        c34 
    FROM
        students
    where
        c34 in(
            ?, ?,?,?
        ) 
    order by
        id desc) o 
group by
    c34;

和我的Java代码。

private final void retrieveStudents(){
    final List result = currentSession()
            .createSQLQuery("SELECT id as id,c03 as c03,c34 as c34 FROM (SELECT id,c34,c03 FROM students where c34 in(:filters) order by id desc) o group by c34;")
            .setParameterList("filters",Arrays.asList(74,1812))
            .list();
    result.forEach(this::consumer1);
}

查询就是OK。返回一个objets数组,我可以迭代,但我想返回一个Student对象,所以我添加。

   .addEntity(Student.class)

但是错误就是抛出

Column 'ACTIVE' not found.

我也尝试过.addScalar,但同样的事情发生了。

.addScalar("id",org.hibernate.type.IntegerType.INSTANCE)
.addScalar("c03",org.hibernate.type.DateType.INSTANCE)

这是来自学生的专栏,但不是在投影我的问题我怎么能这样做我只是认为以某种方式应用别名将Hibernate填充学生实体。

我想要的是一个Student对象,其中填充了id,c03,c34值。

我做错了可能吗?

1 个答案:

答案 0 :(得分:9)

对于此用例,您不希望hibernate将Student视为实体,而是将其视为DTO。

为此,请勿使用addEntity方法,而应使用setResultTransfomer

final List result = currentSession()
        .createSQLQuery("SELECT id as id,c03 as c03,c34 as c34 " + 
                         "FROM (SELECT id,c34,c03 FROM students " + 
                               "where c34 in(:filters) " + 
                               "order by id desc) o group by c34")
        .setParameterList("filters",Arrays.asList(74,1812))
        .addScalar("id",org.hibernate.type.IntegerType.INSTANCE)
        .addScalar("c03",org.hibernate.type.DateType.INSTANCE)
        .addScalar("c34",org.hibernate.type.DateType.INSTANCE)
        .setResultTransformer(Transformers.aliasToBean(Student.class))
        .list();

这适用于非实体类,只要该类具有与投影列的名称匹配的setter,并且有一个no-arg构造函数。我从未在实体课上测试过这个。

如果你没有setter,但是这3个字段的构造函数,你可以使用:

// choose here the right constructor
java.lang.reflect.Constructor constructor = Student.class.getConstructors()...
// ...
.setResultTransformer(new AliasToBeanConstructorResultTransformer(constructor));

代替。

编辑: 我不会将实体用作DTO(但为此用例创建特定的DTO):如果您的某个服务认为实体是以常规方式加载(因此已完全初始化),请对其进行一些修改(更新a例如),并保存实体?

在最好的情况下,一个不可为空的字段(在数据库端)将不会被初始化,并且您将获得ConstraintViolationException并触发回滚,从而保证您的数据安全。

在最糟糕的情况下,您将通过设置null实体的所有字段,但三个已加载的字段来破坏您的数据。