java - 我可以使用 Hibernate 的 Criteria 在 from 子句中生成子查询吗?

标签 java hibernate criteria

我们在项目中经常使用 Criteria 来生成动态查询。我真的很喜欢表达查询的方式。问题是我们发现这个特定的查询不能使用基于 clientId 的索引,所以我们需要改变它。这是有效的非索引查询:

public List<EventInstance> getEventInstances(Date from, Date to, Integer clientId) {
    Session session = this.getSession();

    Criteria criteria = session.createCriteria(EventInstance.class);

    if(clientId != null){

        criteria.add(Restrictions.disjunction()
            .add(Restrictions.eq("clientId", clientId))
            .add(Restrictions.eq("team1ClientId", clientId))
            .add(Restrictions.eq("team2ClientId", clientId))
            );
    }

    if(from != null){
        criteria.add(Restrictions.ge("startTime", from));
    }

    if(to != null){
        criteria.add(Restrictions.le("startTime", to));
    }

    @SuppressWarnings("unchecked")
    List<EventInstance> events = criteria.list();

    this.releaseSession(session);
    return events;
}

此查询只能使用 startTime 索引,不能使用任何 clientId 的索引。我发现以下形式的查询有效地使用了我们的索引,我想使用条件创建此查询:

select * from ( select * from eventInstance where (clientId = 8 or team1ClientId = 8 or team2ClientId = 8) ) evtalias where evtalias.startTime < now()

我已经能够使用这段代码在 WHERE 子句中进行子选择:

public List<EventInstance> getEventInstances(Date from, Date to, Integer clientId){
    Session session = this.getSession();

    DetachedCriteria subSelectClient = DetachedCriteria.forClass(EventInstance.class);
    if(clientId != null){
        subSelectClient.add(Restrictions.disjunction()
            .add(Restrictions.eq("clientId", clientId))
            .add(Restrictions.eq("team1ClientId", clientId))
            .add(Restrictions.eq("team2ClientId", clientId))
            )
            .setProjection(Property.forName("id"));
    }


    Criteria criteria = session.createCriteria(EventInstance.class);

    if(clientId != null){
        criteria.add(Property.forName("id").in(subSelectClient));
    }

    if(from != null){
        criteria.add(Restrictions.ge("startTime", from));
    }

    if(to != null){
        criteria.add(Restrictions.le("startTime", to));
    }

    @SuppressWarnings("unchecked")
    List<EventInstance> events = criteria.list();

    this.releaseSession(session);
    return events;
}

这会生成如下查询:

select * from eventInstance this_ where this_.id in (select this_.id as y0_ from eventInstance this_ where (this_.clientId=8 or this_.team1ClientId=8 or this_.team2ClientId=8)) and this_.startTime<=now();

它在使用索引方面比我原来的查询更糟糕,并且没有在 FROM 中进行子选择。

所以我的问题是,我可以在标准中执行此操作,还是我坚持使用 HQL 甚至 native SQL。或者,如果您知道如何创建一个可以解决我的问题的索引,但我从 mysql 文档中了解到这是不可能的。

这是我要创建的目标查询的解释输出:

mysql> explain select * from ( select * from eventInstance where (clientId = 8 or     team1ClientId = 8 or team2ClientId = 8) ) evtalias where evtalias.startTime < now();
+----+-------------+---------------+-------------+-------------------------------+-----    ------------------+---------+------+------+------------------------------------------------    --------------+
| id | select_type | table         | type        | possible_keys                 | key                    | key_len | ref  | rows | Extra                                                        |
+----+-------------+---------------+-------------+-------------------------------+-----------------------+---------+------+------+--------------------------------------------------------------+
|  1 | PRIMARY     | <derived2>    | ALL         | NULL                          | NULL                   | NULL    | NULL |  288 | Using where                                                  |
|  2 | DERIVED     | eventInstance | index_merge | eijoin2,ei_client,team2,team1 | ei_client,team1,team2 | 5,5,5   | NULL |  300 | Using union(ei_client,team1,team2); Using where; Using index |
+----+-------------+---------------+-------------+-------------------------------+-----------------------+---------+------+------+--------------------------------------------------------------+
2 rows in set (0.00 sec)

这是 hibernate 条件子查询的解释:

+----+--------------------+-------+-----------------+---------------------------------------+---------+---------+------+-------+-------------+
| id | select_type        | table | type            | possible_keys                         | key     | key_len | ref  | rows  | Extra       |
+----+--------------------+-------+-----------------+---------------------------------------+---------+---------+------+-------+-------------+
|  1 | PRIMARY            | this_ | ALL             | ei3                                   | NULL    | NULL    | NULL | 49434 | Using where |
|  2 | DEPENDENT SUBQUERY | this_ | unique_subquery | PRIMARY,eijoin2,ei_client,team2,team1 | PRIMARY | 4       | func |     1 | Using where |
+----+--------------------+-------+-----------------+---------------------------------------+---------+---------+------+-------+-------------+
2 rows in set (0.00 sec)

最佳答案

据我所知,Criteria 和 HQL 都不能在 from 子句中生成带有子查询的查询,因此您必须使用 native SQL。

关于java - 我可以使用 Hibernate 的 Criteria 在 from 子句中生成子查询吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9084870/

相关文章:

mysql - 如何使用一个条件查询对多列求和?

Hibernate Criteria 连接查询

java - 单独的接口(interface)和实现 emf ecore

java - 使键盘自动出现

java - 有没有办法获取用 Graphics2D 绘制的椭圆的坐标?

java - Spring + JPA + SQL View

java - 测试用例后回滚种子数据插入

java - 在 JPA 中的各个列上使用 DISTINCT 关键字

java - 在hibernate实体类中实现Serialized接口(interface)

hibernate - GORM标准按绝对值排序