как использовать сопоставитель примеров данных Spring для атрибута списка - проблема с запросом

Я хотел бы спросить, как использовать exampleMatcher для класса с атрибутом List. Предположим, у нас есть пользователь, который может иметь несколько ролей одновременно. Я хочу получить всех пользователей с ролью пользователя из БД

сущности

@Entity(name = "UserEntity")
public class User {
    Private Long id;
    private String name;
    private String surname;

    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn
    private Address address;

    @ManyToMany(cascade = CascadeType.MERGE, fetch = FetchType.EAGER)
    @JoinColumn
    private List<UserRole> roles;
}

@Entity
public class UserRole {
    private Long id;    
    private String name;
}

Я отправляю класс User с некоторыми атрибутами в getExampleEntity. Я пытаюсь отправить список выбранных ролей из пользовательского интерфейса.

функция в контроллере

@Override
    protected User getExampleEntity() {
        User clonedUser = new User();
        List<UserRole> selectedRole = new ArrayList<>();
        // this cycle just find and add all roles in db based on selection from UI
        for (Long roleID : selectedUserRoleIDs)
           selectedRole.add(userRoleService.find(roleID));
        clonedUser.setRoles(selectedRole);
        return clonedUser;
    }

Функция из JpaRepository, которая вызывает функцию findByExample с примером Matcher.

    @Override
    public List<TObjectType> findByExample(int first, int pageSize, String sortField, Sort.Direction sortOrder, TObjectType type)
    {
        PageRequest pageRequest = getPageRequest(first, pageSize, sortField, sortOrder);
        ExampleMatcher exampleMatcher = getExampleMatcher();
        Example<TObjectType> example = Example.of(type, exampleMatcher);
        return repository.findAll(example, pageRequest).getContent();
    }

    /**
     * Generates an example matcher for the instance of {@link TObjectType}.
     * This can be overriden if a custom matcher is needed! The default property matcher ignores the "id" path and ignores null values.
     * @return
     */
    protected ExampleMatcher getExampleMatcher() {
        return ExampleMatcher.matching()
                .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING)
                .withIgnoreNullValues();

    }

Это работает как сон, если вы отправите пользователя с именем/фамилией атрибута или даже любым атрибутом в классе Address, но это не работает с ролями списка. Я буду признателен за любые советы, как решить эту проблему и как я могу использовать findByExample с массивом TObjectType в качестве атрибута. Большое спасибо

РЕДАКТИРОВАТЬ: Я нашел проблему. Есть код функции репозитория.findAll (org.springframework.data.repository.query.QueryByExampleExecutor#findAll)

@Override
    public <S extends T> Page<S> findAll(Example<S> example, Pageable pageable) {

        ExampleSpecification<S> spec = new ExampleSpecification<S>(example);
        Class<S> probeType = example.getProbeType();
        TypedQuery<S> query = getQuery(new ExampleSpecification<S>(example), probeType, pageable);

        return pageable == null ? new PageImpl<S>(query.getResultList()) : readPage(query, probeType, pageable, spec);
    }

Сгенерированный запрос не включает атрибут списка, но я понятия не имею, почему, и он включен в объект примера. Есть ли у кого-нибудь опыт решения этой проблемы? Я предполагаю, что есть только проблема с настройкой/аннотацией.


person smeidak    schedule 03.02.2017    source источник
comment
У меня тот же вопрос, что и у вас. Я видел в документации, хотя там написано ссылка В настоящее время для сопоставления свойств можно использовать только свойства SingularAttribute. Я попытался исследовать свойства SingularAttribute, но подумал, что это может относиться к исключению списков...   -  person ejgreenwald    schedule 20.08.2017
comment
Вы нашли решение этой проблемы?! Ваш вопрос уместен, и мне действительно интересно, что вы на самом деле сделали.   -  person Thodoris    schedule 22.02.2018


Ответы (1)


Вы должны попробовать использовать трансформатор в первую очередь. Пример ниже для Mongodb, но вы можете увидеть подход. В моем случае класс User содержит список ролей в виде строк:

final ExampleMatcher matcher = ExampleMatcher.matching()
                .withIgnoreNullValues()
                .withMatcher("roles", match -> match.transform(source -> ((BasicDBList) source).iterator().next()).caseSensitive());

        users = userRepository.findAll(Example.of(criteria, matcher), pageRequest);
person Igor Bljahhin    schedule 05.03.2018
comment
1. Что такое BasicDBList? 2. Когда вы говорите, что класс пользователя содержит список ролей в виде строк, вы имеете в виду List<String> roles;? Но вопрос касается List<UserRole> roles; - person naXa; 06.11.2018
comment
Мой пример для Mongodb, используйте его для вдохновения. BasicDBList — это класс из драйвера MongoDB. - person Igor Bljahhin; 07.11.2018
comment
Я был бы счастлив использовать его. Но проблема в том, что я этого не понимаю... Не могли бы вы объяснить эту часть match -> match.transform(source -> ((BasicDBList) source).iterator().next())? - person naXa; 07.11.2018
comment
Чтобы избежать ошибки неконвертируемого типа, используйте match -> match.transform(source -> Optional.of(((BasicDBList) source.get()).iterator().next())).exact() - person 阿尔曼; 07.04.2019
comment
говорит, создайте итератор метода в классе BasicDBList - person Akhil; 07.06.2021