通过示例和投影进行休眠查询

时间:2020-03-05 18:59:12  来源:igfitidea点击:

简而言之:休眠状态不支持投影和示例查询吗?我发现了这篇文章:

代码是这样的:

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。

我已经尝试了几种方法,并搜索了问题跟踪器,但对此一无所获。

我什至尝试使用Projection别名和Transformers,但是它不起作用:

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));

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

解决方案

回答

我可以看到用户类别吗?这只是使用下面的限制。我不明白为什么限制与示例之间确实有什么不同(我认为示例中默认情况下会忽略空字段)。

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]);
}

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

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

回答

当我们使用与对象属性同名的别名时,似乎会发生此问题。 Hibernate似乎选择了别名并在sql中使用它。我发现这里和这里都记录了该文档,尽管我不确定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_":无效的标识符

但是,当我更改使用" 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 ? )

而已!一个很简单的解决一个痛苦的问题的方法。我不知道此修复程序将如何转换为示例问题查询,但它可能使我们更接近。

回答

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

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

它可以正常工作,而无需逐项处理。我得到的是

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:无法解析属性:diff异常。解决方法也不起作用。

PS:由于我找不到有关在Hibernate中使用QBE的详尽文档,因此以上所有内容主要是反复试验方法

回答

真正的问题在于,休眠状态下存在一个错误,该错误在where子句中使用选择列表别名:

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

万一有人降落在这里寻找答案,请看票。它花费了5年的时间解决,但从理论上讲它将在下一个版本中发布,然后我怀疑问题将消失。