简体   繁体   中英

HQL: How to query certain fields when one of those fields is a one-to-many List?

I am having difficulty writing a HQL query to select ONLY the caseid , title , and caseStatus fields from my Cases entity. The cases returned have to be distinct based on caseid. I do not want the name and userid fields to be included. I also do not want to use Lazy fetching for caseid , title , and caseStatus fields. Note that the caseStatus field is a one-to-many List. Below are the entities. The getters/setters are omitted to save space.

@Entity
@Table(name = "Cases")
public class Cases {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "caseid", nullable = false)
    private Integer caseid;
    private Integer userid;
    private String name;
    private String title;
    @OrderBy("caseStatusId DESC")
    @OneToMany(mappedBy = "cases", fetch = FetchType.EAGER)
    private List<CaseStatus> caseStatus;
}

@Entity
@Table(name = "CaseStatus")
public class CaseStatus {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "caseStatusId", nullable = false)
    private Integer caseStatusId;
    private String info;
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "caseid")
    private Cases cases;
}

My goal is to retrieve a distinct List<Cases> or List<Object[]> of the Cases entity containing only caseid , title , and a List<CaseStatus> . The List<CaseStatus> will contain CaseStatus objects with all of its fields populated.

public List<Object[]> getCases(String title) {
    TypedQuery<Object[]> q = em.createQuery("select distinct c.caseid, c.title, cs "
        + "FROM Cases c join c.caseStatus cs "
        + "where c.title like :title", Object[].class);
    q.setParameter("title", "%" + title + "%");
    List<Object[]> results = q.getResultList();
    return results;
}

The above method is close, but not correct because rather than returning a List<CaseStatus> in one of the indexes, it is only returning a single CaseStatus entity.

For example, if my DB contains a single Case with a List<CaseStatus> having a size of n for example, the results will be similar to the example below:

Example of results I'm getting now. Not correct:

        List<Object[]> index 0:
            Contains an Object[] where:
                Object[0] = {some caseid}
                Object[1] = {some title}
                Object[2] = {1st CaseStatus}
        List<Object[]> index 1:
            Contains an Object[] where:
                Object[0] = {same caseid as the one found in index 0 above}
                Object[1] = {same title as the one found in index 0 above}
                Object[2] = {2nd CaseStatus}
        ...
        List<Object[]> index n-1:
            Contains an Object[] where:
                Object[0] = {same caseid as all the previous}
                Object[1] = {same title as all the previous}
                Object[2] = {nth CaseStatus}

Example of results I hope to achieve:

        List<Object[]> index 0:
            Contains an Object[] where:
                Object[0] = {unique caseid}
                Object[1] = {some title}
                Object[2] = List<CaseStatus> with size of n

Updated the question. Instead of name , title , and List<CaseStatus> , the fields I want to retrieve are caseid , title , and List<CaseStatus> . caseid is the primary key of Cases.

I found various threads Select Collections with HQL - hibernate forum and Select collections with HQL - stackoverflow . It's pretty much the problem I ran into. Looks like no one found a solution in these threads.

Hibernates a bit confused about the query; in HQL do your join like this (apologies, I've not been able to test before posting due to wonky computer, but you should get the idea)

select distinct c from Cases c left join fetch c.caseStatus cs where....

the "fetch" makes it eager. Note that this will return an array of type Cases. You where clauses look about right.

In fact HQL is fully object-oriented and uses your classes structure in the Query, so by writing c.caseStatus HQL expects that your Cases class has a caseStatus property, which is wrong because it's a collection.

If you take a look at Hibernate HQL documentation you can see that:

Compared with SQL, however, HQL is fully object-oriented and understands notions like inheritance, polymorphism and association.

I think what you need to do here is to change your query so it matches your classes structures:

    Query q = em.createQuery("select distinct c.name, c.title, cs.caseStatus FROM Cases c left join c.caseStatus where "
        + "c.name like :name and "
        + "c.title like :title");

Correct syntax should be

TypedQuery<Object[]> q = em.createQuery("select c.name, c.title, cs FROM Cases c "
                + "join c.caseStatus cs where "
                + "c.name = :name and "
                + "c.title = :title", Object[].class);

Return type will be List<Object[]> , where in first index of Object[] is c.name, second is c.title and third is associated caseStatus entity. It is possible to query for multiple instances (rows).

We need JOIN because relationship between CaseStatus and Case is mapped via collection.

SELECT cs
FROM Case c JOIN c.cases cs;

Why don't you just use

Query q = em.createQuery("select distinct c from Cases c where "
            + "c.name like :name and "
            + "c.title like :title");

Just try this. This may be a naive approach but should be able to solve the problem. You may be getting more fields than you required but the return type would be list of Cases.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM