【问题标题】:Seam EntityQuery Many-to-Many Joins, Distinct, and OracleSeam EntityQuery 多对多连接、Distinct 和 Oracle
【发布时间】:2011-10-09 21:44:11
【问题描述】:

我是一个已经建立项目的 Seam 新手,所以我使用的很多代码都是借用的,我并不总是完全确定事情是如何工作的。我的问题是我正在使用从 EntityQuery 扩展的查询对象来支持具有搜索和排序功能的列表页面,该功能需要在多对多关系和单独的多对一关系中进行搜索,这也必须用于种类。因为必须加入多对多关系以允许搜索功能,所以查询返回每个分配的重复记录。这没什么大不了的,因为我只是在 ejbql 中添加了“distinct”并且效果很好。但是,当我尝试按其他多对一关系排序时,Oracle 会抛出错误。当使用 distinct 关键字 http://ora-01791.ora-code.com/http://oraclequirks.blogspot.com/2009/04/ora-01791-not-selected-expression.html 时,Oracle 似乎不会接受不在 select 子句中的按列排序。

以下是实体中定义的关系:[Subject m:m JobFunction](显然是通过分配表 [Subject o:m Subject_JobFunction m:o JobFunction])和 [Subject m:o Type]。因为我需要通过 JobFunction 搜索 Subject,所以它加入了 ejbql,它要求 distinct 关键字仅将不同的 Subjects 返回到列表页面。当我尝试按 Type.name 排序(通过多对一关系)时,结果查询使 Oracle 生气并抛出“ORA-01791: not a SELECTed expression”错误。主题查询代码:

@Override
public String getEjbql() {
    return "select subject from Subject subject left outer join subject.jobFunctions as jobFunction";
}

@Override
@SuppressWarnings("rawtypes")
public List<ValueExpression> getRestrictions() {
    ValueExpression[] RESTRICTIONS = { 
            createValueExpression("lower(subject.name) like #{subjectQuery.prepRestriction(subjectQuery.subject.name)}"), 
            createValueExpression("subject.active = #{subjectQuery.active}"), 
            createValueExpression("subject.type.name = #{subjectQuery.typeName}"), 
            createValueExpression("jobFunction.name = #{subjectQuery.jobFunctionName}")
            };
    return Arrays.asList(RESTRICTIONS);

}

当我在用户通过前端按类型名称排序时设置查询顺序时:

"#{subjectQuery.order=='UPPER(subject.type.name) asc'}"

我收到 Oracle 错误。如果我从 ejbql 中取出不同的,排序工作正常,但我得到重复的主题记录。当我添加 distinct 关键字时,列表可以正常工作,没有重复记录,但排序会引发错误。有没有人对我如何重构 ejbql 以返回不带 distinct 关键字的不同记录以使排序愉快,或者如何进行排序而不使 Oracle 对查询中引用的排序列不在 select 子句中感到生气有任何建议?我已经阅读了几个地方,我的答案可能在 Hibernate Criteria API 中,但我不知道如何在扩展的 EntityQuery 类的上下文中利用它来完成我想要完成的任务。请帮忙!

【问题讨论】:

    标签: oracle many-to-many seam


    【解决方案1】:

    如果您要添加 DISTINCT,则说明有问题。

    “因为必须加入多对多关系才能实现搜索功能,所以查询会为每个分配返回重复记录。”

    假设一个人可以从事多个项目,而一个项目可以有很多人。 “人/项目”具有独特性。如果您想要在项目 A 或 B(或两者)中工作的人员列表,那么您可能会得到

    FRED/PROJ_A
    BILL/PROJ_A
    FRED/PROJ_B
    TOM/PROJ_B
    BILL/PROJ_C
    

    如果您只显示名称(不显示项目),您仍然可以按项目订购,但您会看到

    FRED
    BILL
    FRED
    TOM
    BILL
    

    如果你做一个 DISTINCT,你不能再按项目排序,因为你不知道 FRED 是来自 PROJ_A 还是 PROJ_B 或者 BILL 是在 TOM 之前(基于 PROJ_A)还是在 TOM 之后(基于PROJ_C)。

    所以删除 DISTINCT 并始终显示您要订购的列(因为这样您就会明白为什么重复项实际上不是重复项)。

    【讨论】:

    • 谢谢,我实际上并没有按多对多关系排序,当我按另一个未添加到 Hibernate 选择的加入列进行排序时,问题来自 Oracle。 oracle 的一个怪癖是,当您使用 distinct 关键字时,这种情况被认为是错误的。我找到了解决办法。另外,我不应该使用“重复记录”这个语言。我确实意识到由于关系,记录是唯一的,我只是说您在前端看到“重复”,因为连接仅用于搜索功能,而不是用于显示信息。
    【解决方案2】:

    我不确定生成的查询有何不同,但我找到了答案。我不知道休眠的 fetch 命令,它修复了对 distinct 关键字的需求(再次,不确定如何,也许通过子查询?)。将ejbql更改为:

    @Override
    public String getEjbql() {
        return "select subject from Subject subject left join fetch subject.jobFunctions jobFunction";
    }
    

    不再需要 distinct,因此,Oracle 不会抱怨按列排序不在 select 子句中。列表按预期工作,排序列工作!耶!

    不出所料,我在 stackoverflow 上找到了答案。问题并不完全相同,但 hql 语法对我有用:HQL order by within a collection

    【讨论】:

      猜你喜欢
      • 2011-01-30
      • 2011-10-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-05
      • 1970-01-01
      • 1970-01-01
      • 2014-03-13
      • 1970-01-01
      相关资源
      最近更新 更多