【问题标题】:Hibernate Criteria Api SubqueriesHibernate Criteria Api 子查询
【发布时间】:2019-04-24 02:05:48
【问题描述】:

我目前正在开展一个项目,将一些遗留的 jdbc 选择语句转移到使用 Hibernate 及其标准 api。

两个相关的表列和 SQL 查询看起来像:

-QUERIES-
primaryId

-QUERYDETAILS-
primaryId
linkedQueryId -> Foreign key references queries.primaryId
value1
value2

select * 
from queries q 
where q.primaryId not in (SELECT qd.linkedQueryId 
                          FROM querydetails qd 
                          WHERE (qd.value1 LIKE 'PROMPT%' 
                                 OR qd.value2 LIKE 'PROMPT%'));

我的实体关系如下:

@Table("queries")
public class QueryEntity{

    @Id
    @Column
    private Long primaryId;
    @OneToMany(targetEntity = QueryDetailEntity.class, mappedBy = "query", fetch = FetchType.EAGER)
    private Set<QueryDetailEntities> queryDetails;

    //..getters/setters..

}

@Entity
@Table(name = "queryDetails")
public class QueryDetailEntity {
    @Id
    @Column
    private Long primaryId;

    @ManyToOne(targetEntity = QueryEntity.class)
    private QueryEntity query;

@Column(name="value1")
private String value1;

@Column(name="value2")
private String value2;

    //..getters/setters..

}

我正在尝试以这种方式使用标准 api:

Criteria crit = sessionFactory.getCurrentSession().createCriteria(QueryEntity.class);

DetachedCriteria subQuery = DetachedCriteria.forClass(QueryDetailEntity.class);
LogicalExpression hasPrompt = Restrictions.or(Restrictions.ilike("value1", "PROMPT%"),
        Restrictions.ilike("value2", "PROMPT%"));
subQuery.add(hasPrompt);
Criterion subQueryCrit = Subqueries.notIn("queryDetails", subQuery);
crit.add(subQueryCrit);

List<QueryMainEntity> entities = (List<QueryMainEntity>) crit.list();
System.out.println("# of results = " + entities.size());

我在 crit.list() 行上得到一个 NullPointerException,看起来像

Exception in thread "main" java.lang.NullPointerException
    at org.hibernate.loader.criteria.CriteriaQueryTranslator.getProjectedTypes(CriteriaQueryTranslator.java:362)
    at org.hibernate.criterion.SubqueryExpression.createAndSetInnerQuery(SubqueryExpression.java:153)
    at org.hibernate.criterion.SubqueryExpression.toSqlString(SubqueryExpression.java:69)
    at org.hibernate.loader.criteria.CriteriaQueryTranslator.getWhereCondition(CriteriaQueryTranslator.java:380)
    at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:114)
    at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:83)
    at org.hibernate.loader.criteria.CriteriaLoader.<init>(CriteriaLoader.java:92)
    at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1687)
    at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347)

现在,我认为可以肯定地说我错误地使用了 Criteria Api/Detached Query Api,但我不确定“正确”的做法是什么,因为 Hibernate Docs 仅简要介绍了标准api 子查询。

我意识到这是一个很长的问题,但我认为它似乎把问题的所有相关方面都放在了问题上(我试图通过 Criteria API、表、实体表示的查询)。

【问题讨论】:

    标签: java hibernate criteria


    【解决方案1】:

    试一试:

    DetachedCriteria d = DetachedCriteria.forClass(QueryDetailEntity.class, "qd");
    d.setProjection(Projections.projectionList().add(Projections.property("qd.query")));
    d.add(Restrictions.or(Restrictions.like("qd.value1", "PROMPT%"), Restrictions.like("qd.value2", "PROMPT%")));
    
    criteria = session.createCriteria(QueryEntity.class, "q");
    criteria.add(Subqueries.propertyNotIn("q.primaryId", d));
    criteria.list();
    

    以下使用的是属性名,而不是列名:

    qd.query
    qd.value1
    qd.value2
    q.primaryId
    

    附带说明,如果这不是动态生成的查询,您是否考虑过使用 HQL 代替?

    【讨论】:

    • 我使用 NOT EXISTS 类型子查询找到了相同(或类似)的解决方案。让我绊倒的部分是从子查询中设置投影。与这个问题有些无关,但是在我使用这个解决方案之后我遇到了问题,因为子表(querydetails)在带回比我实际预期的更多的记录时被外部连接。为了解决这个问题,我将 QueryDetailEntities#queryDetails 的获取策略更改为具有注释 @Fetch(FetchMode.SELECT)
    猜你喜欢
    • 1970-01-01
    • 2021-02-03
    • 2012-02-15
    • 2019-04-01
    • 2012-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多