JPA Спецификация поиска в списке строк содержит - PullRequest
1 голос
/ 27 сентября 2019

У меня есть следующая сущность:

@Entity
@Table(name = "my_entity");
public class MyEntity {
    // some fields
    @Column(name = "languages")
    @Convert(converter = StringToListConverter.class)
    private List<String> languages;
}

Таблица SQL:

CREATE TABLE my_entity (
    id VARCHAR(255) PRIMARY KEY,
    // some fields
    languages VARCHAR(255) DEFAULT NULL
);

Поле languages содержит список значений, разделенных запятыми EN,FR,NO

Моя задача - выбрать записи, содержащие какой-то язык.Например, в нативном SQL я хотел бы использовать этот SQL:

SELECT * FROM my_entity e WHERE e.languages LIKE CONCAT('%', 'EN', '%');

Я пытался сделать это, используя Спецификацию:

Specification<MyEntity> specification = (root, query, cb) -> {
    final Path<Collection<String>> langs = root.get("languages");
    // also I tried root.joinList
    return cb.isMember("EN", langs);
};

repository.findAll(specification);

Но я получаю следующую ошибку:

unknown collection expression type [org.hibernate.jpa.criteria.path.SingularAttributePath]; nested exception is java.lang.IllegalArgumentException: unknown collection expression type [org.hibernate.jpa.criteria.path.SingularAttributePath]

StringToListConverter выглядит следующим образом:

@Converter
public class StringToListConverter implements AttributeConverter<List<String>, String> {

@Override
public String convertToDatabaseColumn(List<String> list) {
    if(list==null)
        return null;
    return String.join(",", list);
}

@Override
public List<String> convertToEntityAttribute(String joined) {
    if(joined==null)
        return null;
    return new ArrayList<>(Arrays.asList(joined.split(",")));
}

}

Репозиторий:

public class MyEntityRepository extends PagingAndSortingRepository<Address, String>, JpaSpecificationExecutor<MyEntity> {

}

Как решить эту проблему?

1 Ответ

0 голосов
/ 29 сентября 2019

Существует довольно старая проблема открытого спящего режима по этому поводу: https://hibernate.atlassian.net/browse/HHH-9991

К сожалению, единственный найденный мной обходной путь - это использовать вторичное сопоставление только для чтения для языков в вашей сущности и использовать его вСпецификация.

@Entity
@Table(name = "my_entity");
public class MyEntity {
    // some fields
    @Column(name = "languages")
    @Convert(converter = StringToListConverter.class)
    private List<String> languages;

    @Column(name = "languages", insertable = false, updatable = false)
    private String languagesString; //No need for setter

}

Критерии:

Specification<MyEntity> specification = (root, query, cb) -> {
    final Path<String> path = root.get("languagesString");
    return cb.like(path, "%EN%");
};

repository.findAll(specification);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...