【问题标题】:Java Hibernate createSQLQuery using addEntityJava Hibernate createSQLQuery 使用 addEntity
【发布时间】:2017-06-01 09:59:12
【问题描述】:

我需要应用与此类似的 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);
}

查询没问题。返回一个我可以迭代的对象数组,但我想返回一个学生对象,所以我添加了。

   .addEntity(Student.class)

但是会抛出一个错误,上面写着

Column 'ACTIVE' not found.

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

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

这是来自 Student 的列,但不在投影上

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

我做错了什么有可能吗?

【问题讨论】:

  • 答案见下文,但最简单的方法是从学生表中选择所有列(即选择 *)。然后你可以得到你的实体。从性能的角度来看,选择一些额外的列很少有什么大不了的。

标签: java hibernate


【解决方案1】:

对于这个用例,您不希望 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();

这适用于非实体类,前提是该类具有与投影列的名称匹配的设置器,并且有一个无参数构造函数。我从未在实体类上测试过。

如果你没有设置器,但有这 3 个字段的构造器,你可以使用:

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

改为。

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

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

在最坏的情况下,将实体的所有字段设置为null 会损坏数据,但加载的三个字段除外。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-13
    • 2014-09-24
    • 2017-11-22
    • 1970-01-01
    • 2011-02-06
    • 2017-05-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多