Reputation: 13
I have an entity Company
with type represented by enum CompanyType
.
Database is Postgres and it is represented as enum type there.
I use JPA/Hibernate and its repositories.
Note that I am new to JPA, Hibernate and Kotlin.
I am trying to create custom @Query
where I need to select companies where type (the enum) is in list of possible types. I am, however, encountering various error regarding type casting in SQL and/or syntax of the @Query
.
Main part of the data class Company
in Kotlin (did not copy any other attributes including id):
@Entity(name = "Company")
@Table(name = "company")
data class Company(
@Enumerated(EnumType.STRING)
@NotNull
@Column(name = "type", nullable = false, columnDefinition = "company_type")
val type: CompanyType = CompanyType.OTHER
) : Serializable
Enum CompanyType
in Kotlin:
enum class CompanyType(value: Int) {
BUSINESS(1),
TOWN(2),
NONPROFIT(3),
RESEARCH(4),
OTHER(5)
}
Enum company_type
in Postgres:
CREATE TYPE public.company_type AS ENUM (
'BUSINESS',
'TOWN',
'NONPROFIT',
'RESEARCH',
'OTHER'
);
CREATE CAST (character varying AS public.company_type) WITH INOUT AS ASSIGNMENT;
JPA Repository with my initial attempt:
@Repository
interface CompanyDAO : PagingAndSortingRepository<Company> {
@Query("SELECT c FROM #{#entityName} c " +
"WHERE c.type IN ?1"
)
fun findAllByTypeIn(types: List<CompanyType>, pageable: Pageable): Page<Company>
}
which compiles but once executed following error occurs:
ERROR: operator does not exist: company_type = character varying
So I tried to cast it, but do not know how exactly...
@Query("SELECT c FROM #{#entityName} c " +
"WHERE c.type IN cast(?1 AS company_type[])"
)
results in error in compile time:
antlr.MismatchedTokenException: expecting EOF, found ')'
and trying
@Query("SELECT c FROM #{#entityName} c " +
"WHERE c.type IN ?1\\:\\:company_type[]"
)
results in
org.hibernate.QueryException: unexpected char: '\'
How to create such query that takes list of enums and returns such entities that have the value equal to any of items in the list?
Upvotes: 1
Views: 1713
Reputation: 3310
Would it help to create the cast as IMPLICIT instead of as ASSIGNMENT so that it is used in comparisons as well?
CREATE CAST (character varying as days) WITH INOUT AS IMPLICIT;
Upvotes: 0
Reputation: 804
This error is coming from Postgres:
ERROR: operator does not exist: company_type = character varying
To fix this, you can create a custom operator for company_type in Postgres, and not change anything in your code. Like this:
CREATE FUNCTION ctype_compare(company_type, text)
RETURNS boolean
AS '
select cast($1 as text) = $2;
'
LANGUAGE sql IMMUTABLE;
CREATE OPERATOR = (
leftarg = company_type,
rightarg = text,
procedure = company_type_compare
);
With that, you can in fact remove the @Query and Hibernate will do the right thing. If you can't create custom operator, maybe because you don't have the right permissions, then you have to change your query to this:
@Query("SELECT c FROM #{#entityName} c " +
"WHERE cast (c.type as text) IN ?1")
And then you have to fix your argument type to String.
Page<Company> findAllByTypeIn(List<String> types, Pageable pageable);
And to call your DAO method, you pass the correct type:
List<String> types = new ArrayList();
types.add(CompanyType.OTHER.toString());
types.add(CompanyType.BUSINESS.toString());
Page<Company> companies = dao.findAllByTypeIn(types, Pageable.unpaged());
I did this in Java, not Kotlin. But it should work for you.
Upvotes: 3