【问题标题】:ORA-01791 on Hibernate Query关于休眠查询的 ORA-01791
【发布时间】:2013-07-05 08:05:20
【问题描述】:

我的代码是:

Criteria criteriaA = getHibernateSession().createCriteria(entityA.class, "aaa");
Criteria criteriaB = criteriaA.createCriteria("entityB").setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY); // It seems that the result transformer don't affect the code...

criteriaA.add( -- some restriction --)

if (orderById) {
    criteriaB.addOrder(Order.desc("id"));
}

if (!orderById && orderByDate) {
    criteriaB.addOrder(Order.desc("date"));
}

criteriaA.setProjection(Projections.distinct(Projections.property("entityB")));

entityA 和 entityB 具有 oneToMany 关系(一个 entityB 可能有 0..* entityA),但我只能从 B 导航到 A(项目限制.. 无法更改)。
现在,问题是我不需要在返回的结果中重复,我需要对我的结果进行排序。
奇怪的事实是 ORA-01791(告诉我有一个不正确的 orderby)我仅在按日期排序时启动,按 id 排序并没有给我任何问题,但两者都是我想要区分的实体的属性! 为什么我可以按 id 排序但不能按日期排序??
还有其他方法可以做我想做的事情吗?

---- 编辑 -----
正如maby建议的那样,我查看了生成的查询:

DEBUG [org.hibernate.SQL]
select distinct this_.BBB_ID as y0_
from TB_ENTITY_A this_ 
inner join TB_ENTITY_B entityB_ on this_.BBB_ID=entityB_.BBB_ID 
where this_.ANOTHER_ID=? and lower(this_.AAA_VALUE) like ? and this_.AAA_ID in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
order by entityB_.BBB_DATE asc

所以,我的 distinct where 仅适用于外键的 id..
如何强制 Hibernate 选择所有字段?
如果我这样做:

criteriaB.list();

而不是

criteriaA.list():

我会丢失来自条件 A 的过滤器吗?
我也在考虑尝试在 Projection 中设置 entityB 中的所有字段,但我不确定 hibernate 是否可以将结果转换为实体。

【问题讨论】:

  • +1 为解决方案,我将建议自己进行子选择。你也可以把它当作自己的答案。
  • 好了,我已经完成了:)

标签: sql hibernate


【解决方案1】:

http://ora-01791.ora-code.com/ 说:

在此上下文中,所有 ORDER BY 项必须是常量,SELECT 列表 表达式,或操作数为常量或 SELECT 的表达式 列出表达式

我猜测你/hibernate 没有选择date。如果有,能否将生成的 SQL 添加到问题中?

【讨论】:

  • 在正常情况下它应该可以工作,但是在这种特殊情况下,通过使用 DISTINCT 查询规划器不知道它将选择哪一行,因此无法使用日期作为排序.
【解决方案2】:

使用 SQL 关键字作为表名或字段名时会出现奇怪的问题。这可能就是这里发生的事情。只需尝试在您的实体属性上添加@Column(name = "date_")

【讨论】:

  • 已经有:@javax.persistence.Column(name = "AAA_DATE", nullable = false, insertable = true, updatable = true) @javax.persistence.Temporal(javax.persistence.TemporalType. TIMESTAMP) public java.util.Date getDate() { 返回日期; }
  • 我还说所有实体属性都注释到表格字段
【解决方案3】:

mabi 的猜测是正确的。

您要做的是生成一个如下所示的查询:

select this_.BBB_ID as y0_, min(entityB_.BBB_DATE) as min_date
from TB_ENTITY_A this_ 
inner join TB_ENTITY_B entityB_ on this_.BBB_ID=entityB_.BBB_ID 
where this_.ANOTHER_ID=? and lower(this_.AAA_VALUE) like ? 
  and this_.AAA_ID in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
group by this_.BBB_ID
order by min_date asc

虽然不知道如何在 Hibernate 中做到这一点。

如果 Hibernate 无法处理为获取 ID 返回的两列,那么这样的查询应该可以工作:

select y0_ 
    from(
        select this_.BBB_ID as y0_, min(entityB_.BBB_DATE) as min_date
            from TB_ENTITY_A this_ 
                inner join TB_ENTITY_B entityB_ on this_.BBB_ID=entityB_.BBB_ID 
            where this_.ANOTHER_ID=? and lower(this_.AAA_VALUE) like ? 
              and this_.AAA_ID in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            group by this_.BBB_ID
    ) a
order by min_date asc

但同样,如何在 Hibernate 中执行此操作,我不知道。它认为可以添加自定义 SQL/HQL,因此您应该能够以某种方式创建它。

【讨论】:

  • 但是让我们假设用hibernate实现这个查询,我的疑问是:如果在第一个查询hibernate中使用返回给查询的id并恢复实体,如果我用id和日期进行查询, hibernate 可以做同样的事情吗?
  • 好问题。我对 Hibernate 不是很精通,所以我不能说
  • 这很有趣,我也不知道如何获得这样的查询,但我发现返回的结果没有输入,因此将正确的投影添加到条件中的命令 criteriaB.list()没有抛出任何异常,但是使用前面的 sql 它能够将返回的对象投射到 entityA,而使用投影技巧,投射失败。
  • 我正在考虑以编程方式从 entityA 创建到 entityB 的连接,因此我的基本标准设置为我想要区分的实体
【解决方案4】:

按照 mabi 的建议,我回复了我的问题以发布我的解决方案:

---- 已解决-----

我改变了组织查询的方式:我为多方实体创建了一个分离的条件,并使用子查询检索另一个实体:

DetachedCriteria criteriaA = DetachedCriteria.forClass(EntityA.class, "aaa");
criteriaA.add( -- some restriction --);
criteriaA.setProjection(Projections.property("entityB"));

Criteria criteriaB = getHibernateSession().createCriteria(EntityB.class, "bbb");
criteriaB.add(Property.forName("id").in(criteriaA));

所以我不需要一个独特的并且可以从实体 B 中对我想要的所有字段进行排序。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-08-19
    • 1970-01-01
    • 1970-01-01
    • 2011-01-13
    • 2011-08-09
    相关资源
    最近更新 更多