Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use JPA Enum in a JPQL where clause?

Tags:

jpa

jpql

I have an enum as an attribute of an Entity. When I try to use the enum in a JPQL query, it gives an error. What is the correct method to use except passing it as a parameter?

Enum is

package com.divudi.data;

public enum Sex {
    Male,
    Female,
    Unknown,
    Other,
}

Entity is

package com.divudi.entity.lab;

import com.divudi.data.Sex;
import com.divudi.entity.Item;
import com.divudi.entity.WebUser;
import java.io.Serializable;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.Temporal;

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class InvestigationItemValueFlag extends InvestigationItemValue implements Serializable {

    private static final long serialVersionUID = 1L;
    @Enumerated(EnumType.STRING)
    Sex sex;
    @ManyToOne
    InvestigationItem investigationItemOfLabelType;
    @ManyToOne
    private InvestigationItem investigationItemOfValueType;
    @ManyToOne
    InvestigationItem investigationItemOfFlagType;
    @ManyToOne
    Item item;
    long fromAge;
    long toAge;
    @Lob
    private String flagMessage;
    @Lob
    String highMessage;
    @Lob
    String lowMessage;
    @Lob
    String normalMessage;
    boolean displayFlagMessage;
    boolean displayHighMessage;
    boolean displayLowMessage;
    boolean displayNormalMessage;

    public InvestigationItem getInvestigationItemOfLabelType() {
        return investigationItemOfLabelType;
    }

    public void setInvestigationItemOfLabelType(InvestigationItem investigationItemOfLabelType) {
        this.investigationItemOfLabelType = investigationItemOfLabelType;
    }



    public String getHighMessage() {
        return highMessage;
    }

    public void setHighMessage(String highMessage) {
        this.highMessage = highMessage;
    }

    public String getLowMessage() {
        return lowMessage;
    }

    public void setLowMessage(String lowMessage) {
        this.lowMessage = lowMessage;
    }

    public String getNormalMessage() {
        return normalMessage;
    }

    public void setNormalMessage(String normalMessage) {
        this.normalMessage = normalMessage;
    }

    public boolean isDisplayFlagMessage() {
        return displayFlagMessage;
    }

    public void setDisplayFlagMessage(boolean displayFlagMessage) {
        this.displayFlagMessage = displayFlagMessage;
    }

    public boolean isDisplayHighMessage() {
        return displayHighMessage;
    }

    public void setDisplayHighMessage(boolean displayHighMessage) {
        this.displayHighMessage = displayHighMessage;
    }

    public boolean isDisplayLowMessage() {
        return displayLowMessage;
    }

    public void setDisplayLowMessage(boolean displayLowMessage) {
        this.displayLowMessage = displayLowMessage;
    }

    public boolean isDisplayNormalMessage() {
        return displayNormalMessage;
    }

    public void setDisplayNormalMessage(boolean displayNormalMessage) {
        this.displayNormalMessage = displayNormalMessage;
    }





    public Item getItem() {
        return item;
    }

    public void setItem(Item item) {
        this.item = item;
    }



    public InvestigationItemValueFlag() {
    }

    public Sex getSex() {
        return sex;
    }

    public void setSex(Sex sex) {
        this.sex = sex;
    }

    public long getFromAge() {
        return fromAge;
    }

    public void setFromAge(long fromAge) {
        this.fromAge = fromAge;
    }

    public long getToAge() {
        return toAge;
    }

    public void setToAge(long toAge) {
        this.toAge = toAge;
    }

    public String getFlagMessage() {
        return flagMessage;
    }

    public void setFlagMessage(String flagMessage) {
        this.flagMessage = flagMessage;
    }

    public InvestigationItem getInvestigationItemOfValueType() {
        return investigationItemOfValueType;
    }

    public void setInvestigationItemOfValueType(InvestigationItem investigationItemOfValueType) {
        this.investigationItemOfValueType = investigationItemOfValueType;
    }

    public InvestigationItem getInvestigationItemOfFlagType() {
        return investigationItemOfFlagType;
    }

    public void setInvestigationItemOfFlagType(InvestigationItem investigationItemOfFlagType) {
        this.investigationItemOfFlagType = investigationItemOfFlagType;
    }





}

JSF Managed bean is as follows (Relevant code only)

public String getPatientDynamicLabel(InvestigationItem ii, Patient p) {
    String dl;
    String sql;
    dl = ii.getName();
    long ageInDays = commonFunctions.calculateAgeInDays(p.getPerson().getDob(), Calendar.getInstance().getTime());
    sql = "select f from InvestigationItemValueFlag f where  f.fromAge < " + ageInDays + " and f.toAge > " + ageInDays + " and f.investigationItemOfLabelType.id = " + ii.getId();
    List<InvestigationItemValueFlag> fs = getIivfFacade().findBySQL(sql);
    for (InvestigationItemValueFlag f : fs) {
        if (f.getSex() == p.getPerson().getSex()) {
            dl = f.getFlagMessage();
        }
    }
    return dl;
}

Error is

java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager: 
Exception Description: Error compiling the query [select f from InvestigationItemValueFlag f where f.sex = com.divudi.data.Male and f.fromAge < 12419 and f.toAge > 12419 and f.investigationItemOfLabelType.id = 2678], line 1, column 57: unknown identification variable [com]. The FROM clause of the query does not declare an identification variable [com].
like image 373
Buddhika Ariyaratne Avatar asked Jul 20 '13 06:07

Buddhika Ariyaratne


People also ask

How can we send enum value in JSON?

All you have to do is create a static method annotated with @JsonCreator in your enum. This should accept a parameter (the enum value) and return the corresponding enum. This method overrides the default mapping of Enum name to a json attribute .

Can we use inner join in JPQL?

JPQL provides an additional type of identification variable, a join variable, which represent a more limited iteration over specified collections of objects. In JPQL, JOIN can only appear in a FROM clause. The INNER keyword is optional (i.e. INNER JOIN is equivalent to JOIN).

How are enums stored in database?

By default, when an enum is a part of an entity, JPA maps its values into numbers using the ordinal() method. What it means is that without customizations JPA stores enum value as numbers. These numbers are associated with the order in which you define values in the enum.


1 Answers

You shouldn't use string concatenation to pass parameters to a query. You should use parameters (named, preferrably):

String jpql = 
    "select f from InvestigationItemValueFlag f"
    + " where f.sex = :sex"
    + " and ...";
Query query = em.createQuery(jpql);
query.setParameter("sex", Sex.Male);

That will take care of proper escaping, correct SQL generation (the enum could be mapped as a string or as an ordinal), and avoid JPQL injection attacks.

Also please don't name something sql or findBySQL whan it's actually JPQL.

like image 124
JB Nizet Avatar answered Sep 19 '22 03:09

JB Nizet