【问题标题】:Hibernate Query By Example and ProjectionsHibernate Query By Example 和 Projections
【发布时间】:2025-12-10 22:10:01
【问题描述】:

简而言之:hibernate 不支持投影和示例查询?我找到了这篇文章:

代码是这样的:

User usr = new User();
usr.setCity = 'TEST';
getCurrentSession().createCriteria(User.class)
.setProjection( Projections.distinct( Projections.projectionList()
.add( Projections.property("name"), "name")
.add( Projections.property("city"), "city")))
.add( Example.create(usr))

就像另一张海报说的那样,生成的 sql 一直有一个 where 类只引用 y0_= ?而不是 this_.city

我已经尝试了几种方法,并搜索了问题跟踪器,但没有找到任何相关信息。

我什至尝试过使用投影别名和变形金刚,但它不起作用:

User usr = new User();
usr.setCity = 'TEST';
getCurrentSession().createCriteria(User.class)
.setProjection( Projections.distinct( Projections.projectionList()
.add( Projections.property("name"), "name")
.add( Projections.property("city"), "city")))
.add( Example.create(usr)).setResultTransformer(Transformers.aliasToBean(User.class));

有没有人通过示例使用过投影和查询?

【问题讨论】:

  • 你能显示完整的生成的sql吗?
  • 我添加了一个解决方案,其中包含我遇到类似问题时生成的 SQL。

标签: java hibernate criteria projection


【解决方案1】:

我可以看看你的用户类吗?这只是使用下面的限制。我不明白为什么 Restrictions 与 Example 有任何不同(我认为 null 字段在示例中默认会被忽略)。

getCurrentSession().createCriteria(User.class)
.setProjection( Projections.distinct( Projections.projectionList()
.add( Projections.property("name"), "name")
.add( Projections.property("city"), "city")))
.add( Restrictions.eq("city", "TEST")))
.setResultTransformer(Transformers.aliasToBean(User.class))
.list();

我从未使用过 alaistToBean,但我只是读过它。你也可以只循环结果..

List<Object> rows = criteria.list();
for(Object r: rows){
  Object[] row = (Object[]) r;
  Type t = ((<Type>) row[0]);
}

如果需要,您可以自己手动填充用户。

如果没有更多信息来诊断问题,很难调查问题。

【讨论】:

    【解决方案2】:

    当您有一个与 objects 属性同名的别名时,问题似乎会发生。 Hibernate 似乎选择了别名并在 sql 中使用它。我发现这个记录在案的 herehere,我认为这是 Hibernate 中的一个错误,尽管我不确定 Hibernate 团队是否同意。

    无论哪种方式,我都找到了一个适合我的简单解决方法。你的旅费可能会改变。详细信息如下,我试图简化此示例的代码,因此对于任何错误或拼写错误,我深表歉意:

    Criteria criteria = session.createCriteria(MyClass.class)
        .setProjection(Projections.projectionList()
            .add(Projections.property("sectionHeader"), "sectionHeader")
            .add(Projections.property("subSectionHeader"), "subSectionHeader")
            .add(Projections.property("sectionNumber"), "sectionNumber"))
        .add(Restrictions.ilike("sectionHeader", sectionHeaderVar)) // <- Problem!
        .setResultTransformer(Transformers.aliasToBean(MyDTO.class));
    

    会产生这个 sql:

    select
        this_.SECTION_HEADER as y1_,
        this_.SUB_SECTION_HEADER as y2_,
        this_.SECTION_NUMBER as y3_,
    from
        MY_TABLE this_ 
    where
        ( lower(y1_) like ? ) 
    

    导致错误的原因:java.sql.SQLException: ORA-00904: "Y1_": invalid identifier

    但是,当我将限制更改为使用“this”时,如下所示:

    Criteria criteria = session.createCriteria(MyClass.class)
        .setProjection(Projections.projectionList()
            .add(Projections.property("sectionHeader"), "sectionHeader")
            .add(Projections.property("subSectionHeader"), "subSectionHeader")
            .add(Projections.property("sectionNumber"), "sectionNumber"))
        .add(Restrictions.ilike("this.sectionHeader", sectionHeaderVar)) // <- Problem Solved!
        .setResultTransformer(Transformers.aliasToBean(MyDTO.class));
    

    它产生了以下sql,我的问题就解决了。

    select
        this_.SECTION_HEADER as y1_,
        this_.SUB_SECTION_HEADER as y2_,
        this_.SECTION_NUMBER as y3_,
    from
        MY_TABLE this_ 
    where
        ( lower(this_.SECTION_HEADER) like ? ) 
    

    就是这样!一个非常简单的解决一个痛苦的问题。我不知道这个修复会如何转化为示例问题的查询,但它可能会让你更接近。

    【讨论】:

    • 保罗:我很高兴它有帮助。我很惊讶这个答案一直被忽视,只要它似乎是一个大问题,而且这个解决方案既不直观也不记录。
    • Hibernate 的相关 bug 为 hibernate.onjira.com/browse/HHH-817,并已在 Hibernate 3.6.0Beta4 版本中标记为已修复。
    • @RyanCook 嗨!此解决方案有效,但我想知道是否有使用示例的解决方法,因为我们可以有多达 10 个过滤器(即 10 个限制),并且我们必须验证每个字段是否为空或空)。跨度>
    • 我在这个问题上已经杀死了 2 天。 this 关键字很好地解决了这个问题。非常感谢@Ryan
    • Order.asc("sectionHeader") 有另一个问题。当我在 Projection, Restriction & Order 中使用相同的属性时。 !!
    【解决方案3】:

    我面临着类似的问题。我正在使用按示例查询,我想按自定义字段对结果进行排序。在 SQL 中,我会执行以下操作:

    select pageNo, abs(pageNo - 434) as diff
    from relA
    where year = 2009
    order by diff
    

    没有 order-by-clause 也能正常工作。我得到的是

    Criteria crit = getSession().createCriteria(Entity.class);
    crit.add(exampleObject);
    ProjectionList pl = Projections.projectionList();
    pl.add( Projections.property("id") );
    pl.add(Projections.sqlProjection("abs(`pageNo`-"+pageNo+") as diff", new String[] {"diff"}, types ));
    crit.setProjection(pl);
    

    但是当我添加时

    crit.addOrder(Order.asc("diff"));
    

    我得到一个 org.hibernate.QueryException: could not resolve property: diff 异常。 this 的解决方法也不起作用。

    PS:由于我找不到任何关于使用 QBE for Hibernate 的详细文档,以上所有内容主要是试错法

    【讨论】:

      【解决方案4】:

      这里真正的问题是hibernate中有一个错误,它在where子句中使用了选择列表别名:

      http://opensource.atlassian.com/projects/hibernate/browse/HHH-817

      万一有人来这里寻找答案,去看看票。修复花了 5 年时间,但理论上它会在下一个版本中出现,然后我怀疑你的问题会消失。

      【讨论】:

        【解决方案5】:

        我真的不这么认为,我能找到的是“这个”这个词。导致休眠在其查询中不包含任何限制,这意味着它获得了所有记录列表。关于被报告的休眠错误,我可以看到它被报告为已修复,但我完全无法下载补丁。

        【讨论】:

          【解决方案6】:
          ProjectionList pl = Projections.projectionList();
          pl.add(Projections.property("id"));
          pl.add(Projections.sqlProjection("abs(`pageNo`-" + pageNo + ") as diff", new String[] {"diff"}, types ), diff); ---- solution
          crit.addOrder(Order.asc("diff"));
          crit.setProjection(pl);
          

          【讨论】:

          • 在 sqlProjection 之后添加别名,用于排序