简体   繁体   中英

Query ElementCollection of Enum by using JPA Criteria API

I'm working of a web application for a car dealer. I have a Car class with a field which contain a set of security enums.

public class Car {
    @Id
    @GeneratedValue
    private Long id;

    @NotNull(message = "{year}")
    @Min(value = 1950)
    @Max(value = 2020)
    @Column(nullable = false)
    private int year;

    @NotNull()
    @Column(nullable = false)
    private String make;

    @NotNull()
    @Column(nullable = false)
    private String model;

    @NotNull()
    @Min(value = 0)
    @Max(value = 1000000)
    @Column(nullable = false)
    private int kilometres;

    @Column(nullable = false)
    private int price;


    @NotNull()
    @Enumerated(EnumType.STRING)
    private Gearbox gearbox;

    @ElementCollection(fetch = FetchType.EAGER)
    @Enumerated(EnumType.STRING)
    @CollectionTable(name="SECURITY")
    @Column(name="TYPE")
    private Set<Security> securityList = new HashSet<Security>();

    @NotNull()
    @Column(nullable = false)
    private String description;

    @OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY, orphanRemoval = true)
    private List<Picture> pictureList = new ArrayList<Picture>();

   // Getters and setters + help methods..

The Security enum is like:

public enum Security {

    ABS("abs"),
    AIRBAG("airbag"),
    ANTISPIN("antispin"),
    CENTRAL_LOCKING("centralLocking"),
    REMOTE_ALARM("remoteAlarm"),
    FOUR_WHEEL("fourWheel"),
    PARKING_ASSISTANCE("parkingAssistance"),
    SERVICE_MANUAL("serviceManual"),
    STABILITY_CONTROL("stabilityControl"),
    XENON_LIGHT("xenonLight");

    private String label;

    private Security(String label) {

    }

    public String getLabel() {
        return label;
    }
}

In the web application, I will create a search page, where the users is able to define required Securitiy parts and a manufacturer pattern (make field in Car class) . For instance, a user might search for Cars which have a make pattern according to "Volkswagen" and Security with at least ABS and REMOTE_ALARM.

My problem is that I am not sure how to create the query using the criteria API. I guess it should start like:

public List<Car> searchCars(String makePattern, Set<Security> requiredSecuirtySet) {

        CriteriaBuilder cb = em.getCriteriaBuilder();

        CriteriaQuery<Car> cq = cb.createQuery(Car.class);
        Root<Car> _car = cq.from(Car.class);


        // Give me some help here please =)


        return em.createQuery(cq).getResultList();
}

Can you please help me? I also have a meta model over the Car class.

Best regards and thanks in advance!

You can use collections as parameters so maybe this will work:

TypedQuery<Car> q = em.createQuery("select c from Car c where c.make = :make and c.securityList in :secutiryList", Car.class);
q.setParameter("make", makePattern);
q.setParameter("securityList", requiredSecuirtySet);

return q.getResultList();

I haven't tested this so I'm not sure it will work. It is based on this question . I also haven't worked with the criteria API so I didn't know how to 'translate' it.

Here's a shot at the query with the criteria API:

public List<Car> searchCars(String makePattern,
        Set<Security> requiredSecuirtySet)
{
    CriteriaBuilder builder = em.getCriteriaBuilder();

    CriteriaQuery<Car> query = builder.createQuery(Car.class);
    Root<Car> car = query.from(Car.class);
    query.select(car).where(
            builder.equal(car.get("make"), makePattern),
            car.get("securityList").in(requiredSecuirtySet));
    return em.createQuery(query).getResultList();
}

Thanks siebz0r!

I was modifying your code a little bit since your code returns all Cars that has 1 or more security (and not all), ie returns all cars which has a securityList that contain at least a subset of the securityList.

Here is my code:

public List<Car> searchCars(String makePattern, Set<Security> requiredSecuirtySet) {

        CriteriaBuilder cb = em.getCriteriaBuilder();

        CriteriaQuery<Car> cq = cb.createQuery(Car.class);
        Root<Car> car = cq.from(Car.class);

        Predicate criteria = cb.conjunction();
        for (Security security : carQueryData.getSecurityCriteria()) {
            criteria = cb.and(criteria, car.get(Car_.securityList).in(security) );
        }
        // Add more predicates, for instance:
        // for (Equipment equipment : carQueryData.getEquipmentsCriteria()) {
        //    criteria = cb.and(criteria, car.get(Car_.equipmentList).in(equipment) );
        // }

        Predicate makePredicate = cb.equal(car.get(Car_.make), makePattern);

        cq.select(car).where(makePredicate, criteria);

        return em.createQuery(cq).getResultList();
    }

Best regards

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