简体   繁体   English

如何使用JPA和Hibernate使用映射为ORDINAL的Enum参数进行查询

[英]How to query using an Enum parameter mapped as ORDINAL using JPA and Hibernate

I need to get data from database by enum type. 我需要通过枚举类型从数据库中获取数据。 I have following enum: 我有以下枚举:

public enum ShopType {
    VANS("VANS"), ATTICUS("ATTICUS"), FAMOUS("FAMOUS")

    ShopType(String label) {
        this.label = label;
    }

    private String label;

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }
}

In my DAO class i have method which returns list of objects by selected type on jsp page. 在我的DAO类中,我有一个方法,它在jsp页面上按所选类型返回对象列表。 On jsp page i send selected value like String , is it right? jsp页面上我发送选择的值像String ,是不是?

That how looks my method 那怎么看我的方法

@Transactional
public List<Shop> findByType(String type) {
    return sessionFactory.getCurrentSession().createQuery("from Shop where type=" + .....  .list();
}

I don't know how to create right query. 我不知道如何创建正确的查询。 Enum i store in my database like tinyint. Enum i存储在我的数据库中,如tinyint。

Here is a model. 这是一个模型。

@Column(name = "type")
@Enumerated(EnumType.ORDINAL)
private ShopType type;

As you set your enum as ordinal, then in query you should use ordinal. 当你将enum设置为序数时,那么在查询中你应该使用序数。 Example; 例;

@Transactional
public List<Shop> findByType(String type) {
    return sessionFactory.getCurrentSession().createQuery("from Shop where type=" + ShopType.valueOf(type).ordinal()).list();
}

If you change @Enumerated(EnumType.STRING) , then your query will look like; 如果更改@Enumerated(EnumType.STRING) ,那么您的查询将如下所示;

@Transactional
public List<Shop> findByType(String type) {
    return sessionFactory.getCurrentSession().createQuery("from Shop where type=" + ShopType.valueOf(type).name()).list();
}

ShopType.valueOf(type) , This will work only if string type is same as enum name. ShopType.valueOf(type) ,仅当字符串类型与枚举名称相同时才有效。 Also if your label is same as enum name, then you don't need label. 此外,如果您的标签与枚举名称相同,那么您不需要标签。 ShopType.VANS.name() is equals "VANS" and name() method is final, you can be sure that can't be overridden. ShopType.VANS.name()等于"VANS"name()方法是final,可以肯定不能被覆盖。

Just convert String to Enum and use named query parameter 只需将String转换为Enum并使用命名查询参数

@Transactional
public List<Shop> findByType(String type) {
    ShopType enumType = shopTypeFromString(type);
    return sessionFactory.getCurrentSession().createQuery("from Shop where type=:p_type")
        .setParameter("p_type", enumType).list();
}

private ShopType shopTypeFromString(String type) {
    // You can implement this convertion in your own way
    return ShopType.valueOf(type);
}

The problem in your query is that you concatenated the bind parameter value which, apart from causing your issue, may expose your application to SQL injection attacks . 您的查询中的问题是您连接了bind参数值,除了导致您的问题之外,它还可能使您的应用程序暴露于SQL注入攻击

If you write the query using bind parameter values: 如果使用绑定参数值编写查询:

Post post = entityManager.createQuery(
    "select p " +
    "from Post p " +
    "where p.status = :status", Post.class)
.setParameter("status", PostStatus.PENDING)
.getSingleResult();

assertEquals("High-Performance Java Persistence", post.getTitle());

Hibernate will properly use the ORDINAL value in the SQL query: Hibernate将在SQL查询中正确使用ORDINAL值:

Query:["
    select 
        p.id as id1_0_,
        p.status as status2_0_, 
        p.title as title3_0_ 
    from 
        post p 
    where 
        p.status=?
"], 
Params:[
    0
]

For a working example, check out the EnumOrdinalTest in my high-performance-java-persistence GitHub repository . 有关一个工作示例,请查看我high-performance-java-persistence GitHub存储库中EnumOrdinalTest

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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