Во-первых, один предмет домашнего хранения, прежде чем мы начнем ...
Я вижу, что вы ссылались на 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"]
, здесь .Джон имеет объявленный возраст, а Джейн - нет.Конечно, оба человека существуют в кеше (т. Е. Область «Люди»).
Когда я запрашиваю Джона и утверждаю его возраст, я получаю ожидаемый результат .
В качестве альтернативы, когда я запрашиваю Джейн и утверждаю ее возраст, я могу получить 1 из двух значений: null
или 0
, как ожидается (в настоящее время 0
, поскольку я использую нулевой безопасный запрос ).Если я изменю запрос на обычный запрос , тогда возвращаемое значение для age
Джейн будет на самом деле null
, и я могу утверждать так.
Однако, когда мыприступить к опросу несуществующего человека, поведение GemFire понятно;нет результатов.Я проиллюстрировал это двумя различными способами (кроме использования репозитория), используя GemFire QueryService
API напрямую, а затем снова используя SDG удобный GemfireTemplate
класс , который просто оборачивает GemFireAPI запросов (это также метод, который используется Repository под капотом; на самом деле, значение Repositories добавляет возможности сопоставления / преобразования).
Как видите, я должен разобратьсяотсутствие результатов, например, .
В случае с репозиторием, поскольку вы использовали пользовательский запрос, для инфраструктуры репозитория не сразу видно, какая часть (т.е. промежуточный результат запроса) был null
.
Что если у вас было SELECT person.address.city.name FROM ...
?
Является ли человек null
, адрес null
или город null
?Как это должно обрабатываться последовательно?Человек может выйти, но адрес может быть null
, что может оправдать другое поведение, чем если бы человек или город были null
.
На самом деле абстракция Репозиторий обрабатывает null
возвращаемые значения, как видно здесь .
Итак, куда мы пойдем отсюда?
У нас есть несколько вариантов:
Вы могли бы и проверить существование , сначала ...
вернуть personRepository.existsById (bobDoe.getName ())?personRepository.getAge (bobDoe.getName ()): 0;
Вы можете справиться с этим вне репозитория в DAO (возможно, адаптируя / декорируя Репозиторий и делегирование для простых случаев запросов, а не сложных запросов, которые включают использование аннотации @Query
, которую следует использовать с осторожностью).
@ Класс репозитория 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.
}
...
}
Все еще
Другой вариант - предоставить нам дополнительную поддержку в SD, что-то вроде ...
@Nullable Integer getAge(String name);
Или, возможно ...
Optional<Integer> getAge(String name);
Тем не менее, этот подход не решает проблему неоднозначности и потребует больше размышлений.
Что было бы действительно хорошо, если бы OQL обрабатывал оператор Элвиса, что-то вроде (в моем более сложном примере выше) ...
SELECT person? .Address? .City? .Name FROM /Люди ...
В любом случае, я надеюсь, что это даст вам некоторые идеи.Прежде чем двигаться дальше, мне нужно больше подумать над № 3.
Если у вас есть дополнительные вопросы / отзывы / идеи, пожалуйста, укажите их в комментариях или не стесняйтесь подавать билет JIRA .
Спасибо!