Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate @Filter collection of enums

I need to figure out how to apply annotation-based filtering with a parameter list of enums defined as:

@Column(name = "target_status")
@Enumerated(EnumType.STRING)
@Type(type="PGEnumConverter", parameters = {
    @Parameter(name = "enumClassName",
               value = "com.company.model.campaign.CampaignTarget$Status")
})
private Status targetStatus;

So my @FilterDef looks like this:

    @FilterDef(name="filterCampaignTargetByStatuses",
               defaultCondition="target_status in (:statuses)",
               parameters = @ParamDef(name = "statuses", type = "string"))

And when I enable the filter it looks like this:

    session.enableFilter("filterCampaignTargetByStatuses").
    setParameterList("statuses", statuses);

And the Error that I get from hibernate is:

 org.hibernate.HibernateException: Incorrect type for parameter [statuses]

The data is in PostgreSQL and the definition of the type:

CREATE TYPE statuscmp AS ENUM ('ACTIVE','INACTIVE','PAUSED','DRAFT','SCHEDULED','ENDED','ARCHIVED');

I've seen a lot of SO questions about how to do criteria queries and filters against a single Enum value, but none yet about filtering on a set of Enum values. Is there a way to explicitly cast the individual values?

like image 943
gred Avatar asked Jul 23 '15 20:07

gred


1 Answers

You don't have to "cast" the value in general, in fact you just have to pass the values in the form they are stored.

If we assume your field was only annotated as @Enumerated(EnumType.STRING) the column would be a plain varchar field. (Mapping a java type to a postgres enum is another big topic.)

If you now want to compare your list of Status enum instances with the related string values in the db, pass it as collection of strings, in other words, call it's toString() method if it's a java enum.

E.g. this was your enum:

public enum EntityStatus {
    A, B, C;
}

This was your Entity:

import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import org.hibernate.annotations.Filter;
import org.hibernate.annotations.FilterDef;
import org.hibernate.annotations.ParamDef;

@Entity
@FilterDef(name = "byMultipleStates", defaultCondition = "status in (:states)", parameters = @ParamDef(name = "states", type = "string"))
@Filter(name = "byMultipleStates", condition = "status in (:states)")
public class StatusEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;

    @Enumerated(EnumType.STRING)
    private EntityStatus status;

    public long getId() {
        return id;
    }

    public EntityStatus getStatus() {
        return status;
    }

    public void setStatus(EntityStatus status) {
        this.status = status;
    }

}

This could be your code to filter:

public List<StatusEntity> filterByStates(final Set<EntityStatus> states) {
    final Session hibernateSession = entityManager.unwrap(Session.class);
    hibernateSession.enableFilter("byMultipleStates").setParameterList("states",
            states.stream().map(state -> state.toString()).collect(Collectors.toList()));
    final Query query = hibernateSession.createQuery("SELECT e FROM StatusEntity e");

    return query.list();
}

Or in the way before Java 8:

public List<StatusEntity> filterByStates(final Set<EntityStatus> states) {
    final Set<String> statesAsString = new HashSet<>();
    for (final EntityStatus state : states) {
        statesAsString.add(state.toString());
    }

    final Session hibernateSession = entityManager.unwrap(Session.class);
    hibernateSession.enableFilter("byMultipleStates").setParameterList("states", statesAsString);
    final Query query = hibernateSession.createQuery("SELECT e FROM StatusEntity e");

    return query.list();
}

So just filtering for a collection of values is possible.

like image 70
Kevin Peters Avatar answered Nov 04 '22 15:11

Kevin Peters