Как использовать NVL для получения данных из GemFire, когда результат запроса равен нулю

Я использую Spring Data GemFire в проекте и использую репозиторий для извлечения результатов запроса из кеша, как указано здесь: https://docs.spring.io/spring-gemfire/docs/1.3.3.RELEASE/reference/html/gemfire-repositories.html

Ниже представлен мой интерфейс Repository:

@Repository
@Region("someRegion")
public interface SomeRegionRepository  extends GemfireRepository<CustomObject, Object> {

    //Below works when id exists in gemfire region. 
    //But when id does not exists it
    //gives java.lang.IllegalStateException: Unsupported query
    @Query("select a.num from /someRegion a where a.id = $1")
    Integer getNumById(String id);

    //Below returns CustomObject instance when id exists in gemfire region. 
    //But when id does not exists it returns null (Expected)
    CustomObject findById(String id);

}

Можно ли каким-либо образом вернуть 0 или какое-либо другое значение, если для этого ключа в запросе OQL не найдены данные?

Или есть ли способ получить значение null, чтобы я мог обрабатывать его в коде вызывающей стороны, когда нет данных?

Существует нечто, называемое NVL (которое позволяет возвращать другие значения/выражения в случае, если первое выражение оценивается как null) в OQL, указанном здесь: https://gemfire.docs.pivotal.io/97/geode/developing/query_select/the_select_statement.html . Но я не могу получить правильный синтаксис того, как его использовать.

Пожалуйста помоги. Спасибо.


person KCK    schedule 15.02.2019    source источник


Ответы (1)


Во-первых, один предмет домашнего обихода, прежде чем мы начнем...

Я вижу, что вы упомянули Pivotal GemFire 9.7 в справке по документации GemFire ​​выше, но затем ссылаетесь на Spring Data GemFire (SDG) 1.3.3.RELEASE справочные документы. Я очень надеюсь, что вы не пытаетесь использовать SDG 1.3.3.RELEASE с Pivotal GemFire ​​9.7. SDG 1.3.3 устарел, основан на Pivotal GemFire ​​7.0.1 и больше не поддерживается.

Я подозреваю, что вы не используете SDG 1.3.x, поэтому вам, вероятно, следует всегда ссылаться на последнюю документацию, доступную здесь и, в частности, здесь. Даже Поиск Google показывает последние документы.

Кроме того, вы можете обратиться к Spring Data для Pivotal GemFire Матрица совместимости версий для получения более подробной информации. Так или иначе...

Итак, я написал тестовый класс, чтобы лучше понять ваш UC.

В своем тесте я смоделировал класс Person с запрашиваемым ageполе/свойство. У меня есть PersonRepository для типа Person, и я написал запрос, очень похожий на ваш пример выше, для запроса человека по возрасту в обычный, а также null-safe.

Дело в том, что ваше желание защититься от отсутствия результатов, возвращая null или 0, неоднозначно в случае с Хранилищами.

Для 1, если вы вернули несколько результатов (например, как в SELECT a.num FROM /SomeRegion a, то есть без предиката), и результаты не были упорядочены, то у вас не было бы способа узнать, какое значение было null для какого ключа, если вы также не вернули ключ в набор результатов.

Конечно, здесь это не так, и вы уточнили запрос по идентификатору, используя предикат (например, ... WHERE a.id = $1). Однако в этом случае при просмотре запроса (например, SELECT a.num FROM ...) неясно, не было ли результата для данного идентификатора (например, ключа) или просто num было null. Вы действительно не знаете.

Мой тест продолжает иллюстрировать этот момент.

У меня есть 2 человека ["Jon Doe", "Jane Doe"], здесь. У Джона есть заявленный возраст, а у Джейн - нет. Конечно, оба человека существуют в кэше (т.е. в регионе «Люди»).

Когда я запрашиваю Джона и утверждаю его возраст, я получаю ожидаемый результат.

В качестве альтернативы, когда я запрашиваю Джейн и указываю ее возраст, я могу получить одно из двух значений, null или 0, как ожидается здесь (в настоящее время 0, так как я использую нулевой безопасный запрос). Если я изменю запрос на обычный запрос, то возвращаемое значение для age Джейн на самом деле будет null, и я мог утверждать это как таковое.

Однако когда мы приступаем к запросу несуществующего человека, поведение GemFire ​​становится очевидным; нет результатов. Я проиллюстрировал это двумя разными способами (кроме использования репозитория), используя GemFire ​​QueryService API напрямую, а затем снова с помощью удобного GemfireTemplate class, который просто является оболочкой GemFire ​​Query API (это также метод, используемый репозиторием под капотом; на самом деле репозиторий добавляет значение возможностей сопоставления/преобразования).

Как видите, я должен обработать отсутствие результатов для пример.

В случае репозитория, поскольку вы использовали пользовательский запрос, инфраструктуре репозитория не сразу становится понятно, какая часть (то есть промежуточный результат запроса) была null.

Что, если бы у вас было SELECT person.address.city.name FROM ...?

Лицо null, адрес null или город null? Как это должно быть обработано последовательно? Человек может выйти, но адрес может быть null, что может потребовать другого поведения, чем если бы человек или город были null.

На самом деле абстракция Репозиторий обрабатывает null возвращаемых значений, как видно здесь.

Так куда же мы пойдем отсюда?

У нас есть несколько вариантов:

  1. Вы можете выполнить и проверка существования, сначала...

    вернуть personRepository.existsById(bobDoe.getName()) ? personRepository.getAge(bobDoe.getName()): 0;

  2. Вы можете справиться с этим за пределами Репозитория в DAO (возможно, адаптировав/украсив Репозиторий и делегировав его для простых запросов, а не для сложных запросов, которые включают использование аннотации @Query, которые следует использовать с осторожностью).

    @Repository class PersonDao {

    @Autowired
    private PersonRepository personRepository;
    
    Person findById(String name) {
        return this.personRepository.findById(name).orElse(null);
    }
    
    Integer getAge(String name) {
        // Either use the approach in #1, or do https://github.com/jxblum/contacts-application/blob/master/tests-example/src/test/java/example/tests/spring/data/gemfire/NullValueReturningRepositoryQueryMethodIntegrationTests.java#L143-L151.
    }
    
    ...
    

    }

    Все еще

  3. Другим вариантом для нас было бы предоставление дополнительной поддержки в SD, что-то вроде...

    @Nullable Integer getAge(String name);

    Или, возможно...

    Optional<Integer> getAge(String name);

    Тем не менее, этот подход не решает проблему неоднозначности и требует дополнительных размышлений.

  4. Что было бы действительно хорошо, если бы OQL обрабатывал оператор Элвиса, что-то вроде (в моем более сложном примере выше)...

    ВЫБЕРИТЕ человека?.адрес?.город?.имя ОТ /Люди...

В любом случае, я надеюсь, что это даст вам некоторые идеи. Мне нужно будет еще подумать над пунктом 3 выше, прежде чем двигаться дальше.

Если у вас есть дополнительные вопросы/отзывы/идеи, задайте их в комментариях или не стесняйтесь подать заявку на JIRA. .

Спасибо!

person John Blum    schedule 15.02.2019