org.hibernate.criterion - 我需要OR一起使用任意数量的标准吗?

时间:2015-08-05 11:51:01

标签: java oracle hibernate

我有一个使用(很老)hibernate映射到oracle 11数据库的java应用程序。我使用org.hibernate.criterion类来生成我的查询(至少对于这个部分)。

我最近遇到了一个错误,我使用org.hibernate.Criteria生成的一个查询产生了一个非常大的' in'条款。以下是Java控制台如何显示生成的查询:

select this_.foo as foo_1_2_3, this_.bar as bar_2_3_4, this_.id as id_5_6_7
from some_table inner join some_other_table inner join
where blah=bloo and this_.id in (?, ?, ?, ?, ?, ......................... ?, ?, ?, ?) order by this_.id asc

其中?元素的数量> 1000。

此in子句太大,导致我们的数据库中出现ORA-01795: maximum number of expressions in a list is 1000错误。

这是添加' in'的Java代码。条款:

criteria.add(Restrictions.in("id", getMassiveListOfIDs() ) );

(换句话说,我在子句中添加> 1000元素)

根据this stackoverflow question仅使用多个较小的''条款是解决方案。说得通。

我已对此进行了修改,以便在添加' in'之前拆分列表。查询,如下:

    List<Long> listOfIds = getMassiveListOfIDs();

    if(listOfIds.size()>=1000){ 
        List<List<Long>> listOfSublists = this.splitIntoSubArrays(listOfIds); 
        for(List<Long> subArray : listOfSublists){
            criteria.add(Restrictions.in("id", subArray)); 
        }
    }else{
        criteria.add(Restrictions.in("id", listOfIds));
    }

现在生成的查询如下所示:

select this_.foo as foo_1_2_3, this_.bar as bar_2_3_4, this_.id as id_5_6_7
from some_table inner join some_other_table inner join
where blah=bloo and
this_.id in (?, ?, .... ?, ?) 
and this_.id in (?, ?, .... ?, ?) 
and this_.id in (?, ?, .... ?, ?) 
and this_.id in (?, ?, ?, ?, ?, ?) 
order by this_.id asc

其中每个(?, ?, .... ?, ?, ?) 数组实际上包含1000个元素,最后一个是余数。

问题是这些是AND而不是OR我想要OR所有in子句(换句话说,我想获取任何具有在这些子句中列出的id的行),如:

select this_.foo as foo_1_2_3, this_.bar as bar_2_3_4, this_.id as id_5_6_7
from some_table inner join some_other_table inner join
where blah=bloo and (
this_.id in (?, ?, .... ?, ?) 
OR this_.id in (?, ?, .... ?, ?) 
OR this_.id in (?, ?, .... ?, ?) 
OR this_.id in (?, ?, ?, ?, ?, ?) 
) 
order by this_.id asc

我知道我可以这样做:

Criterion c1 = Restrictions.in("id", sublist1);
Criterion c2 = Restrictions.in("id", sublist2);
Criterion c3 = Restrictions.in("id", sublist3);
Criterion c4 = Restrictions.in("id", sublist4);

Criterion or1 = Restrictions.or(c1, c2);
Criterion or2 = Restrictions.or(c3, c4);

criteria.add(Restrictions.or(or1, or1) );

但我不知道在编译时listOfIds有多大。 500或10000.

有没有办法

  • 动态生成上面显示的ORing

  • 或任意大小的标准列表并将它们添加到查询中?

我意识到这是一个非常小众的问题,所以我将不胜感激任何帮助或建议。为了说明,我还大量简化了这些例子。

真的,我正在寻找一个Java Code解决方案,而不是改变我的数据库或hibernate映射,如果可能的话。

非常感谢。

2 个答案:

答案 0 :(得分:0)

你需要这样的东西:

if (arguments.size() > 1000) {
            Criterion criterionIn = Restrictions.sqlRestriction("1<>1");
            final List<Serializable> inList = new ArrayList<Serializable>();
            for (int i = 0; i < arguments.size(); i++) {
                inList.add(arguments.get(i));
                if (inList.size() == 1000) {
                    criterionIn = Restrictions.or(criterionIn, Restrictions.in(restriction.getField(), inList));
                    inList.clear();
                }
            }
            if (!inList.isEmpty()) {
                criterionIn = Restrictions.or(criterionIn, Restrictions.in(restriction.getField(), inList));
            }
            final Criterion criterionNotIn = Restrictions.not(criterionIn);
            return criterionNotIn;
        }

您可以在github

上找到完整示例

答案 1 :(得分:0)

结果是一个非常简单的方法,如:

Criterion restriction = Restrictions.in("id", listOfSublists.get(0));

for(int i=1; i<listOfSublists.size(); i++){
    restriction = Restrictions.or(restriction, Restrictions.in("id", listOfSublists.get(i)));
}

工作正常并产生正确的查询。

当我第一次尝试这个问题时,我收到了奇怪的查询,并了解了.or.and方法在示例中如何串联在一起,以及如何将结果查询括起来,但事实证明这很好,这些问题与我在Java中添加限制的方式无关。

下次我在尝试午睡和喝咖啡之前先把它放到堆叠溢出处......