开发者

Java JPA "Error compiling the query" when it uses an enum

The following JPA query doesn't compile:

@NamedQuery(name = "PSA.findBySourceSystem", 
    query = "SELECT p FROM PSA p WHERE p.sourceSystem.id = :sourceSystemId")

p.sourceSystem is the following enum:

public enum SourceSystem {
    FIRST(3, "ABC"), SECOND(9, "DEF"), THIRD(17, "GHI");

    private int id;
    private String code;
    ...
}

and is mapped in PSA's base class:

public class PsaBase implements Serializable {
    @Column(name = "sourceSystemId")
    @Enumerated(EnumType.ORDINAL)
    protected SourceSystem sourceSystem;
    ...
}

The query compiles and runs fine if I replace p.sourceS开发者_运维知识库ystem.id in the query with something more benign.

Thank you in advance for any help.


It shouldn't compile.

You have to resolve the required enum value manually before passing it as a query parameter:

@NamedQuery(name = "PSA.findBySourceSystem",  
    query = "SELECT p FROM PSA p WHERE p.sourceSystem = :sourceSystem") 

.

public enum SourceSystem { 
    ... 
    private static Map<Integer, SourceSystem> valuesById = new HashMap<Integer, SourceSystem>();
    static {
        for (SourceSystem s: values()) 
            valuesById.put(s.id, s);
    }
    public static SourceSystem findById(int id) {
        return valuesById.get(id);
    }
} 

.

em.createNamedQuery("PSA.findBySourceSystem")
    .setParameter("sourceSystem", SourceSystem.findById(sourceSystemId));

EDIT: Since sourceSystem is annotated as @Enumerated(EnumType.ORDINAL), it's stored in the database as the ordinal numbers of the corresponding enum values, therefore FIRST is stored as 0. JPA doesn't directly support using arbitrary field of the enum value to identify it in the database. If your database schema assumes so, you can do the following trick to decouple state of your object from the database schema:

public class PsaBase implements Serializable { 
    protected SourceSystem sourceSystem; 

    @Column(name = "sourceSystemId") 
    public Integer getSourceSystemId() {
        return sourceSystem.getId();
    }

    public void setSourceSystemId(Integer id) {
        this.sourceSystem = SourceSystem.findById(id);
    }
    ... getter and setter of sourceSystem with @Transient ...
} 
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜