Пользовательский запрос JPA / Hibernate со списком перечислений Postgres - PullRequest
0 голосов
/ 17 апреля 2020

У меня есть сущность Company с типом, представленным enum CompanyType. База данных Postgres и представлена ​​в виде типа enum. Я использую JPA / Hibernate и его репозитории. Обратите внимание, что я новичок в JPA, Hibernate и Kotlin.

Я пытаюсь создать пользовательский @Query, где мне нужно выбрать компании, в которых тип (перечисление) находится в списке возможных типов. Однако я сталкиваюсь с различными ошибками, связанными с приведением типов в SQL и / или синтаксисе @Query.

Основная часть класса данных Company в Kotlin (не копировал другие атрибуты, включая идентификатор):

@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

Перечисление CompanyType в Kotlin:

enum class CompanyType(value: Int) {
    BUSSINESS(1),
    TOWN(2),
    NONPROFIT(3),
    RESEARCH(4),
    OTHER(5)
}

Перечисление company_type в Postgres:

CREATE TYPE public.company_type AS ENUM (
    'BUSSINESS',
    'TOWN',
    'NONPROFIT',
    'RESEARCH',
    'OTHER'
);
CREATE CAST (character varying AS public.company_type) WITH INOUT AS ASSIGNMENT;

Репозиторий JPA с моей первоначальной попыткой:

@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>
}

, который компилируется, но после выполнения возникает следующая ошибка:

ERROR: operator does not exist: company_type = character varying

Поэтому я попытался привести его, но не знаю, как именно ...

    @Query("SELECT c FROM #{#entityName} c " +
        "WHERE c.type IN cast(?1 AS company_type[])"
    )

приводит к ошибке во время компиляции:

antlr.MismatchedTokenException: expecting EOF, found ')'

, а попытка

    @Query("SELECT c FROM #{#entityName} c " +
        "WHERE c.type IN ?1\\:\\:company_type[]"
    )

приводит к

org.hibernate.QueryException: unexpected char: '\'

Как создать такой запрос, который принимает список перечислений и возвращает такие объекты, которые имеют значение, равное любому из элементов в списке?

1 Ответ

1 голос
/ 18 апреля 2020

Эта ошибка происходит от Postgres:

ОШИБКА: оператор не существует: company_type = символ меняется

Чтобы исправить это, вы можете создать пользовательский оператор для company_type в Postgres, и ничего не менять в вашем коде. Вот так:

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
);

С этим вы можете фактически удалить @Query, и Hibernate сделает правильные вещи. Если вы не можете создать пользовательский оператор, возможно, из-за того, что у вас нет необходимых прав доступа, вам нужно изменить запрос следующим образом:

    @Query("SELECT c FROM #{#entityName} c " +
        "WHERE cast (c.type as text) IN ?1")

И затем вам нужно будет зафиксировать тип аргумента как String .

    Page<Company> findAllByTypeIn(List<String> types, Pageable pageable);

И чтобы вызвать метод DAO, вы передаете правильный тип:

    List<String> types = new ArrayList();
    types.add(CompanyType.OTHER.toString());
    types.add(CompanyType.BUSSINESS.toString());

    Page<Company> companies = dao.findAllByTypeIn(types, Pageable.unpaged());

Я сделал это в Java, а не Kotlin. Но это должно сработать для вас.

...