Как получить доступ к объекту Gemfire по уникальному значению или набору значений подобъектов

У меня есть запрос, который выглядит так и не работает должным образом. Я пробовал довольно много разных вариантов, но мне что-то не хватает в запросе.

Код репозитория:

@Query("SELECT c FROM /customer c, c.emailAddresses email WHERE email.emailAddress = $1")
List<CustomerEntity> findByEmailAddress(String emailAddress);       

Модель:

public class CustomerEntity {
   @Id
   protected String id;
   private List<CustomerEmailAddressEntity> emailAddresses;      
}

public class CustomerEmailAddressEntity {
   private Long id;
   private String emailAddress;
 }

Стек, который я получаю, выглядит так:

Caused by: java.lang.ClassCastException: com.gemstone.gemfire.cache.query.internal.Undefined cannot be cast to com.gemstone.gemfire.cache.query.SelectResults
    at com.gemstone.gemfire.internal.cache.PRQueryProcessor.executeSequentially(PRQueryProcessor.java:330)
    at com.gemstone.gemfire.internal.cache.PRQueryProcessor.executeQuery(PRQueryProcessor.java:127)
    at com.gemstone.gemfire.internal.cache.PartitionedRegionQueryEvaluator.executeQueryOnLocalNode(PartitionedRegionQueryEvaluator.java:1370)
    at com.gemstone.gemfire.internal.cache.PartitionedRegionQueryEvaluator.executeQueryOnRemoteAndLocalNodes(PartitionedRegionQueryEvaluator.java:339)
    at com.gemstone.gemfire.internal.cache.PartitionedRegionQueryEvaluator.queryBuckets(PartitionedRegionQueryEvaluator.java:442)
    at com.gemstone.gemfire.internal.cache.PartitionedRegion.doExecuteQuery(PartitionedRegion.java:1909)
    at com.gemstone.gemfire.internal.cache.PartitionedRegion.executeQuery(PartitionedRegion.java:1829)
    at com.gemstone.gemfire.cache.query.internal.DefaultQuery.execute(DefaultQuery.java:234)
    at com.gemstone.gemfire.cache.query.internal.DefaultQuery.execute(DefaultQuery.java:195)
    at com.gemstone.gemfire.internal.cache.tier.sockets.BaseCommand.processQueryUsingParams(BaseCommand.java:1402)
    at com.gemstone.gemfire.internal.cache.tier.sockets.BaseCommand.processQuery(BaseCommand.java:1347)
    at com.gemstone.gemfire.internal.cache.tier.sockets.command.Query.cmdExecute(Query.java:88)
    at com.gemstone.gemfire.internal.cache.tier.sockets.BaseCommand.execute(BaseCommand.java:174)
    at com.gemstone.gemfire.internal.cache.tier.sockets.ServerConnection.doNormalMsg(ServerConnection.java:809)
    at com.gemstone.gemfire.internal.cache.tier.sockets.ServerConnection.doOneMessage(ServerConnection.java:940)
    at com.gemstone.gemfire.internal.cache.tier.sockets.ServerConnection.run(ServerConnection.java:1189)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at com.gemstone.gemfire.internal.cache.tier.sockets.AcceptorImpl$1$1.run(AcceptorImpl.java:532)
    at java.lang.Thread.run(Thread.java:724)

Я не уверен, что я делаю неправильно. Любая помощь приветствуется.


person Amita Marconda    schedule 12.02.2015    source источник


Ответы (2)


Хороший улов!

Я бы добавил, что, как правило, свойства массива и коллекции (объект домена приложения) никогда не должны быть нулевыми. Пустой хорошо, но никогда не нуль. Это может быть проблематично для итераций (особенно с циклами foreach, ведущими к довольно неясным NPE, похожим на объекты Wrapper нулевого примитивного типа при автоматической упаковке/распаковке) и, как вы видели, GemFire ​​OQL.

Тем не менее, я согласен, что было бы более информативно и полезно, если бы GemFire ​​определил причину проблемы с запросом или смог обработать нулевую ссылку.

Интересно, что эта проблема может быть специфичной для GemFire ​​7.0.2. Я только что протестировал этот сценарий, используя как GemFire ​​7.0.2, так и (последнюю) GemFire ​​8.1.0.

С 7.0.2 произошло следующее исключение...

org.springframework.dao.InvalidDataAccessApiUsageException: Result object returned from GemfireCallback isn't a SelectResult: [UNDEFINED]
...

Но при работе с GemFire ​​8.1.0 оператор OQL (запрос) работал должным образом, даже когда вложенная коллекция не была инициализирована в моем объекте домена приложения...

class Customer ... {
  Set<Address> addresses;
  ...
}

interface CustomerRepository implements GemfireRepository<Customer, Long> {
  @Query("<trace> SELECT DISTINCT c FROM /Customers c, c.addresses a WHERE a.city = $1")
  List<User> findCustomersInCity(String city);

}

Потом...

customerRepo.findCustomersInCity("Portland");

Я (пере) закодировал своего клиента так, чтобы коллекция «адресов» инициализировалась только в том случае, если был добавлен адрес, и я использовал комбинацию клиентов с адресами и без них в своем тестовом примере.

Таким образом, хотя может показаться, что GemFire ​​8.x справляется с этим, я все же считаю целесообразным правильно инициализировать объект.

person John Blum    schedule 17.02.2015

Причину этого нашел один из скромных архитекторов нашей группы. Это был не плохой запрос, а проблема с данными. У некоторых клиентов были нулевые адреса электронной почты, и Gemfire OQL не смог обработать нулевой элемент коллекции. Было бы лучше, если бы GemfireOQL выдал мне более полезное сообщение об ошибке.

Итак, извлеченные уроки:

Предварительно инициализируйте свои коллекции, прежде чем сохранять их в gemfire 7.

person Amita Marconda    schedule 12.02.2015