简体   繁体   中英

How to use projection and where clause in JPA criteria?

I have entity Person

@Entity(name = "Person")
public class Person {

    @Id
    @GeneratedValue
    private Long id;
    private String name;
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "person")
    private Set<Phone> phones=new HashSet<Phone>();

    public Person() {
    }

    public Person(String name) {
        this.name = name;

    }

Ad entity Phone :

@Entity(name = "Phone")
public class Phone {

    @Id
    @GeneratedValue
    private Long id;

    @Column(name = "`number`")
    private String number;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "person_id", nullable = false)
    private Person person;

    public Phone() {
    }

They have one-to-many relation. Now I want to build in jpa criteria such query:

select p.phones from person p join phone ph where p.name = :name;

So I want to extract Set<Phone> phones from Person entity where person's name is parameter.

I've written this jpa criteria query:

CriteriaBuilder builder = session.getCriteriaBuilder();
        CriteriaQuery<Person> query = builder.createQuery(Person.class);
        Root<Person> root = query.from(Person.class);
        CriteriaQuery<Person> where = query.where(builder.equal(root.get("name"), "Mary Dick"));
        CompoundSelection<Set> projection = builder.construct(Set.class, root.get("phones"));
        where.select(projection); //compile error: The method select(Selection<? extends Person>) in the type CriteriaQuery<Person> is not applicable for the arguments (CompoundSelection<Set>)
    }

But it gives compile error:

The method select(Selection<? extends Person>) in the type CriteriaQuery<Person> is not applicable for the arguments (CompoundSelection<Set>)

How is it correct? Do I need metamodel classes?

CompoundSelection<Y> construct(Class<Y> result, Selection<?>... terms)

This method is useful only when the query would involve certain projections which are not entirely encapsulated by a single entity class. If that is the case, first parameter would be the custom POJO class (with suitable constructor) with fields which corresponding to the select clause of the query.

In this case, the selection is already a part of the entity class. So, you can simply choose the fields you need.

 CriteriaQuery<Person> query = builder.createQuery(Person.class);
 Root<Person> root = query.from(Person.class);
 query.where(builder.equal(root.get("name"), "Mary Dick"));
 query.select(root.get("phones"));

Above query will return a list of person. But if you are looking for just an iterable list of phones, try with a slightly different query.

select ph from phone ph join ph.person p where p.name = :name;

And its equivalent CriteriaQuery:

CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Phone> query = builder.createQuery(Phone.class);
Root<Phone> root = query.from(Phone.class);
Join<Phone, Person> join = root.join(root.get("person"))            
query.where(builder.equal(join.get("name"), "Mary Dick"));

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