Search code examples
jpajpql

Search in key value Entity


Salam,

I have a problem with (key, value) entity searching.

I don't figure out how to write the jpql query to search.. this is my problem

I have document entity, mapped to oneToMany "MetaData" entity

@Entity
public class Document implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name="id_document")
    private Integer idDocument;

    @Column(name="date_enregistrement")
    private Timestamp dateEnregistrement;

    // other columns

    //bi-directional many-to-one association to MetaData
    @OneToMany(mappedBy="document")
    private List<MetaData> metaData;

    /*
     getters and setters
    */
}

and MetaData entity

@Entity
@Table(name="meta_data")
public class MetaData implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @Column(name="id_meta_data")
    private Integer idMetaData;

    @Column(name="key")
    private String key;

    @Column(name="value")
    private String value;

    //bi-directional many-to-one association to Document
    @ManyToOne
    @JoinColumn(name="id_document")
    private Document document;

    /*
     getters and setters
    */

}

What i want to do is to search for documents by providing some metadata as parameters.

examples:

Find documents where sender (key = sender) is Youssef (value = Youssef) And receiver (key) is Hamza (value)

it's possible that the client provides more than two parameters.

Thanks in advace


Solution

  • As key-value pairs can vary in number, I'll suggest to go with CriteraQuery for more flexibilty:

    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Document> query = criteriaBuilder.createQuery(Document.class);
    Root<Document> root = query.from(Document.class);
    Join<Document, MetaData> metadataJoin = root.join("metaData", JoinType.INNER);
    List<Predicate> predicateList = new LinkedList<Predicate>();
    //If a map contains all your key value pairs
    for(Map.Entry<String, String> entry : keyValueMap.entrySet()){
      predicateList.add(
        criteriaBuilder.and(
          criteriaBuilder.equal(metadataJoin.get("key"), entry.getKey()), 
          criteriaBuilder.equal(metadataJoin.get("value"), entry.getValue())
        )
      );
    }
    query.where(criteriaBuilder.or(
      predicateList.toArray(new Predicate[predicateList.size()]))
    )
    query.groupBy(root.get("idDocument"));
    query.having(criteriaBuilder.equal(criteriaBuilder.count(root.get("idDocument")), predicateList.size()));
    List<Document> documentList = entityManager.createQuery(query).getResultList();