Как создавать динамические запросы с помощью репозиториев Spring Data Redis?

Я тестирую Redis с помощью spring-data-redis, используя такие репозитории:

public interface CreditCardRepository extends CrudRepository<CreditCard, String>{
    List<CreditCard> findByIssuer(String issuer);
    List<CreditCard> findByCreditNetwork(String creditNetwork);
    List<CreditCard> findByCreditNetworkAndIssuer(String creditNetwork, String issuer);
}

Вышеупомянутые методы будут запрашивать структуры Redis, такие как:

creditcard:creditNetwork:mastercard
creditcard:creditNetwork:visa
creditcard:issuer:company1
creditcard:issuer:company2

Прямо сейчас мой объект CreditCard содержит два атрибута (эмитент, сеть и идентификатор), поэтому легко искать такие объекты:

private List<CreditCard> searchCardFromCache(CreditCardGetReq req) {
    if (req.getIssuer() != null && req.getNetwork() != null) { 
        return ccRepository.findByIssuerAndCreditNetwork(req.getIssuer(), req.getNetwork().name()); 
    }
    if (req.getIssuer() != null) { 
        return ccRepository.findByIssuer(req.getIssuer()); 
    }
    if (req.getNetwork() != null) { 
        return ccRepository.findByCreditNetwork(req.getNetwork().name()); 
    }
    return null;
}

Однако мне не нравится этот код, так как мне придется создать комбинацию всех свойств, и это будет очень беспорядочно. В будущем я планирую иметь 15 свойств, поэтому цепочка if невозможна.

Я хотел бы спросить вас, как я могу создавать динамические запросы с помощью spring-data-redis, чтобы Redis мог возвращать пересечение на основе свойств объекта лучше, чем проверка каждого свойства?

Пробовали использовать MethodHandle путем жесткого кодирования (я ранее удалил из репозитория findByIssuerAndCreditNetwork) имя метода, которое будет динамически сгенерировано следующим образом:

MethodType methodType = MethodType.methodType(cardList.getClass(), String.class, String.class);
// Dynamic create 'findByIssuerAndCreditNetwork'
MethodHandle methodHandle = MethodHandles.lookup().findVirtual(CreditCardRepository.class, "findByIssuerAndCreditNetwork", methodType);

Но кажется, что MethodHandle не работает, так как я получил ошибку ниже:

java.lang.NoSuchMethodException: такого метода нет: com.creditcard.dao.CreditCardRepository.findByIssuerAndCreditNetwork (String, String) ArrayList / invokeInterface


person Federico Piazza    schedule 28.02.2017    source источник
comment
Интересный вопрос. Поскольку вы определяете фактические правила того, какой метод вызывать, вам все равно нужно будет просмотреть все свойства CreditCardGetReq   -  person Eugene    schedule 01.03.2017
comment
@Eugene, да, мне все равно, что делать обход всех свойств, это простая часть, однако выполнение комбинации findByX - сложная задача. Я попробую создать динамическую строку, такую ​​как findByXAndY dynamic и вызов репо через отражение, сделает трюк, но я чувствую, что здесь что-то не хватает   -  person Federico Piazza    schedule 01.03.2017
comment
На самом деле я тоже думал в этом направлении ... но через MethodHandles, а не через рефлексию, которая будет работать, если у вас есть реальный экземпляр репозитория. Проблема в том, что для обработчиков методов явно нужны аргументы вызова.   -  person Eugene    schedule 01.03.2017
comment
@Eugene, пробовал MethodHandle, но похоже, что это не работает. Также обновили вопрос, указав эти детали   -  person Federico Piazza    schedule 01.03.2017
comment
Я сам этим не пользовался, но RedisCallback и RedisTemplate не дадут вам то, что вы хотите? Хотя он будет менее абстрактным, чем при использовании чистых данных Spring   -  person Leon    schedule 01.03.2017
comment
@Leon, RedisTemplate дает мне то, что я хочу, однако мне нужно создать все обслуживание коллекции, которое подвержено ошибкам и занимает больше времени. Spring-data-redis уже все делает за меня, но минус в том, что его репозитории не динамические.   -  person Federico Piazza    schedule 01.03.2017


Ответы (1)


В настоящий момент нет поддержки для создания динамических запросов. Это немного похоже на Запрос by Example может быть тем, что вы ищете. Spring Data MongoDB и Spring Data JPA уже реализуют запрос по примеру.

Модуль хранилища данных создает запрос для сопоставления с примером объекта домена:

Person person = new Person();                         
person.setFirstname("Dave");                          

Example<Person> example = Example.of(person); 

MongoRepository repo = …
List<Person> result = repo.findAll(example); // returns all objects that with Dave in firstname

Запрос по примеру не поддерживается Spring Data Redis прямо сейчас, но должна быть возможность предоставить базовую поддержку.

Я создал билет DATAREDIS-605, чтобы отслеживать прогресс этой функции.

person mp911de    schedule 01.03.2017
comment
Спасибо, Марк, было бы здорово иметь эту функцию. Я добавил себя в качестве наблюдателя в Jira. - person Federico Piazza; 01.03.2017
comment
Марк, когда эта функция будет выпущена, если вы хотите предоставить версию spring-data-redis и конкретный образец, я мог бы отметить вам этот ответ как принятый, чтобы сообщество знало, как его использовать. - person Federico Piazza; 03.03.2017
comment
Марк, я заметил в заявке Jira, что вы завершили разработку запроса на примере. Это уже доступно? Код, который вы предоставили, такой же, чтобы использовать его с redis данных Spring? Если да, дайте мне знать, чтобы я принял ответ, если нет, можете ли вы предоставить образец кода? Большое спасибо - person Federico Piazza; 10.01.2018
comment
Он доступен в сборке моментальных снимков версии 2.1. Попробуйте, всегда рады получить раннюю обратную связь. - person mp911de; 10.01.2018
comment
вы можете обновить этот ответ в соответствии с выпущенной функцией? - person Federico Piazza; 26.07.2018
comment
@ mp911de - Не могли бы вы посоветовать мне stackoverflow.com/questions/53134556/? - person Jeff Cook; 04.11.2018