Reputation: 23
I have the following entity:
@Entity
public class Person extends BaseEntity {
private static final String PETS_SEPARATOR = ";";
@Id
@Nonnull
private String id;
@Column(name = "pets")
@Convert(converter = StringSetConverter.class)
@Nonnull
private Set<String> pets;
}
And the StringSetConverter basically parses between String (separated by ;) and Set.
Notice that this is inherited code and I cannot easily change the database structure to have the pet relations in a separated table.
This causes having in the database a string like: "DOG;CAT;BIRD". And I want to find all the users that have "CAT", for instance.
So I tried a silly search like this one
Specification<UserEntity> petsSpecification =
(root, criteriaQuery, cb) -> {
return cb.like(root.get("pets"), "%CAT%"));
};
This is not elegant, I'm aware of that, and here we should take into account the separator (what happens if I have another animal called "PERSIAN_CAT"?). But anyway, this is failing with this:
Caused by: java.lang.IllegalArgumentException: Parameter value [CAT] did not match expected type [java.util.Set (n/a)]
So it seems right as long as we are working in Hibernate, and the attribute pets is in fact a Set, not a String. But after looking into the internet and checking the documentation, I cannot see a clear way of making this query using Criteria API. I could use a native query to work with the String instead of the Set and make the "like" approach, but I would like to do it by code, non-depending in the technology of the database.
Upvotes: 1
Views: 6472
Reputation: 3945
You can simply perform a typecast upon the expression, returning a new expression object.
Specification<AttributePerson> rawPetSpecification =
(root, criteriaQuery, cb) -> cb.like(root
.get("pets").as(String.class), "%CAT%");
OR
You could map the Set<String>
column in another property of String
type:
@Column(name = "pets", insertable = false, updatable = false)
private String rawPets;
This column with the attribute insertable = false, updatable = false
as being neither insertable nor updatable, so that its value is not persisted, so you get the stored value. https://stackoverflow.com/a/3805682/2039546
Now you can write a query like this:
Specification<AttributePerson> rawPetSpecification =
(root, criteriaQuery, cb) ->
cb.like(root.get("rawPets"), "%CAT%");
Upvotes: 4