prix
prix

Reputation: 101

Criteria API find Key-Value Pairs in Map

I try to use the Criteria API to create a dynamic JPA-Query. I need to find a key-value pair inside a map of the object. The Object looks similar to the following one.

public class item {
    private UUID id;
    @Column(name = "properties", columnDefinition = "nvarchar")
    private Map<String, Object> properties;
}

enter image description here

I thought I could use the MapJoin join or joinMap:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Item> criteriaQuery = cb.createQuery(Item.class);
Root<Item> itemRoot = criteriaQuery.from(Item.class);
criteriaQuery.select(itemRoot);

Join<String, Object> properties = itemRoot.join("properties");
// or 
//MapJoin<Item, String, Object> properties =  itemRoot.joinMap("properties");

Predicate pre1 = cb.equal(properties.get(ITEM_PROPERTY_1), "123");
Predicate pre2 = cb.equal(properties.get(ITEM_PROPERTY_2), "456");
Predicate propertiesPredicate = cb.and(pre1, pre2);
criteriaQuery.where(propertiesPredicate);
Item item = em.createQuery(criteriaQuery).getSingleResult();

But I've read that this is only for associations. On the join i get an:

IllegalArgumentException: Requested attribute was not a map.

So could sb explain to me, how I will be able to find a key-value pair in a map with the Criteria API?

Edit: I am not able to change anything in the DB.

Upvotes: 1

Views: 1088

Answers (1)

A. A. Jabrams
A. A. Jabrams

Reputation: 1

So I need to guess a little bit because you didn't show us your DB Table, that's why I answer a little bit more freely. And as a disclaimer: it might be easier and it would be more efficient to query a real table instead of an serialized object/json. But I would do it this way:

The Table in MSSQL:

create table ${schema}.myTable
(
    id      bigint identity
            constraint PK_myStuff
            primary key,
    properties nvarchar(max) not null
) go

The Java entity (draft):

public class Item extends AbstractPersistable<...> {
    @Column(name = "properties", columnDefinition = "nvarchar")
    private String properties;
}

The Java Specification:

protected Specification<Item> customFilter(String filterArg) {
    return (root, query, cb) ->
            cb.like(root.get(Item_.properties), filterArg);
  }

This way your query searches the properties for a string pattern.

Info: https://vladmihalcea.com/sql-server-json-hibernate/

Upvotes: 0

Related Questions