Eric
Eric

Reputation: 515

Using JPA Criteria API to return all object where a Collection property contains a certain value

I am trying to dynamicaly create a Specification for my Spring-data-jpa project

Here is my specification for the moment:

public class DemandsSpecs implements Specification<SvDem> {

    private static final Logger LOG = LogManager.getLogger();

    private final DemandsCritera critera;
    private final List<Predicate> predicateList;

    public DemandsSpecs(final DemandsCritera critera) {
        this.critera = critera;
        this.predicateList = new ArrayList<>();
    }

    @Override
    public Predicate toPredicate(final Root<SvDem> root,
                                 final CriteriaQuery<?> query,
                                 final CriteriaBuilder cb) {

        this.predicateList.add(cb.between(root.get(SvDem_.hdCreation), critera.getBegin(), critera.getEnd()));

        if (critera.getSoc() != null) {
            LOG.debug("socId {}", critera.getSoc());
            this.predicateList.add(cb.equal(root.get(SvDem_.socId), critera.getSoc()));
        }

        if (critera.getManagementAct() != null) {
            LOG.debug("actgesId {}", critera.getManagementAct());
            this.predicateList.add(cb.equal(root.get(SvDem_.actgesId), critera.getManagementAct()));
        }

        if (critera.getStatus() != null) {
            LOG.debug("statutId {}", critera.getStatus());
            this.predicateList.add(cb.equal(root.get(SvDem_.statutId), critera.getStatus()));
        }

        if (!StringUtils.isBlank(critera.getId())) {
            LOG.debug("id {}", critera.getId());
            this.predicateList.add(cb.like(root.get(SvDem_.id), '%' + critera.getId() + '%'));
        }

        return query.where(cb.and(predicateList.toArray(new Predicate[predicateList.size()])))
                .orderBy(cb.desc(root.get("hdCreation")))
                .getRestriction();
    }
}

The DemandsCritera also have a String property metadata.

public class DemandsCritera implements Serializable {

    private static final Long serialVersionUID = 1L;

    private Date begin;
    private Date end;
    private RfActges managementAct;
    private String metadata;
    private RfStatut status;
    private RfSoc soc;
    private String id;

    /* getters and setters */
}

SvDem has a property svMetaCollection which is a Collection<SvMeta>.

@Entity
@Table(name = "sv_dem")
public class SvDem implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @Basic(optional = false)
    private String id;
    @Basic(optional = false)
    @Column(name = "HD_CREATION")
    @Temporal(TemporalType.TIMESTAMP)
    private Date hdCreation;

    @Lob
    private String user;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "svDem")
    @JsonManagedReference
    private Collection<SvMeta> svMetaCollection;

    @JoinColumn(name = "ACTGES_ID", referencedColumnName = "ID")
    @ManyToOne(optional = false)
    private RfActges actgesId;

    @JoinColumn(name = "STATUT_ID", referencedColumnName = "ID")
    @ManyToOne(optional = false)
    private RfStatut statutId;

    @JoinColumn(name = "SOC_ID", referencedColumnName = "ID")
    @ManyToOne(optional = false)
    private RfSoc socId;

    /* getters, setters and other irrelevant properties */

}

The SvMeta object has a String property value

@Entity
@Table(name = "sv_meta")
public class SvMeta implements Serializable {

    private static final long serialVersionUID = 1L;
    @EmbeddedId
    protected SvMetaPK svMetaPK;

    @Basic(optional = false)
    @Lob
    private String value;

    @JoinColumn(name = "META_ID", referencedColumnName = "ID", insertable = false, updatable = false)
    @ManyToOne(optional = false)
    private RfMeta rfMeta;

    @JoinColumn(name = "DEM_ID", referencedColumnName = "ID", insertable = false, updatable = false)
    @ManyToOne(optional = false)
    @JsonBackReference
    private SvDem svDem;
}

I want to return all the SvDem where any of its SvMeta has a value equals to the DemandsCritera.metadata.

How can I achieve that?

Upvotes: 4

Views: 2855

Answers (1)

Eric
Eric

Reputation: 515

I just needed to add this to my toPredicate method of DemandsSpecs:

    if (!StringUtils.isBlank(critera.getMetadata())) {
        LOG.debug("metadata {}", critera.getMetadata());
        Join<SvDem, SvMeta> metas = root.join(SvDem_.svMetaCollection);
        this.predicateList.add(cb.equal(metas.get(SvMeta_.value), critera.getMetadata()));
    }

Upvotes: 4

Related Questions