Трансляция в pdx и обратно в прослушивателе событий Apache Geode

В связанном вопросе я задал вопрос о проблеме с клиентом Geode.Net, использующим типы Geode PDX к объектам (объектам домена), и на этот раз у меня возникла проблема с преобразованием объектов в типы Geode PDX. Кажется, что регион может содержать как сериализованные типы объектов pdx, так и другие типы объектов и / или типы внутренних объектов. Думаю, работая с байтовыми смещениями.

В любом случае, эта ссылка показывает способ проверки типов объектов и их обработки:

// get checks Object type and handles each appropriately
Object myObject = myRegion.get(myKey);

либо как экземпляры PDX, либо как типы объектов домена:

if (myObject instanceof PdxInstance) {
  // get returned PdxInstance instead of domain object    
  PdxInstance myPdxInstance = (PdxInstance)myObject;

затем с GetField для экземпляра PDX вы можете обновить только 1 поле, очень хорошо ...

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

else if (myObject instanceof DomainClass) {
// code to handle domain object instance  

При выходе из прослушивателя событий

public void AfterCreate(EntryEvent<TKey, TVal> ev)

В первую очередь я пытаюсь преобразовать ev.NewValue в Pdx или затем в объект домена и получаю одно из следующего:

Когда значение в регионе равно PdxInstance, тогда без if (myObject instanceof PdxInstance), как указано выше, чтобы предотвратить это, приведение IPdxInstance pdx = (IPdxInstance)ev.NewValue дает:

System.InvalidCastException: Unable to cast object of type myObject to type
Apache.Geode.Client.IPdxInstance

Чего и следовало ожидать. Кажется, я нарушил PdxSerialisation myObject, создав регион <key, value> как <string, Object>, хотя myObject расширяет PdxSerializable и запись ключей и значений в регион проходит через ToData() переопределение.

Итак, чтобы иметь дело с myObject напрямую, например myObject = ev.NewValue или myObject.Field1 = ((myObject)(ev.NewValue)).Field1 или подобные варианты, дает:

Cannot implicitly convert type 'TVal' to 'myObject' 
Cannot convert type 'TVal' to 'myObject'

Конечно, преобразование от ev.NewValue к myObject должно быть простым, так что же мне не хватает? В противном случае я должен использовать ev.Key (который выполняет приведение без каких-либо исключений), чтобы снова указать get значение из области в кеше, используя:

IRegion<string, Object> r = cache.GetRegion<string, Object>(region);
return r[key];

Итак, если объект уже указан в TVal типе NewValue, тогда почему я просто не могу получить к нему доступ? :-s


person rupweb    schedule 02.02.2018    source источник
comment
Не могли бы вы опубликовать код, содержащий приведение, которое вызывает это исключение?   -  person Randy May    schedule 03.02.2018
comment
Спасибо за комментарий. Обновил вопрос.   -  person rupweb    schedule 03.02.2018
comment
Вы используете собственный клиент? Я спрашиваю об этом, потому что ваш строковый объект имеет нижний регистр, а ваш AfterCreate - Pascal-Case, что является соглашением .NET. Если это так, возможно, ваша проблема не в PDX. Расширьте ReflectionBasedAutoSerializer и поместите точку останова в ReadTransform, и вы увидите, в каком поле возникает проблема: см. gemfire-native-90.docs.pivotal.io/native/dotnet-caching-api/. Кроме того, если он пытается выполнить приведение к IPdxInstance, у вас должно быть read-serialized = true. Вы уверены, что этого хотите?   -  person Wes Williams    schedule 05.02.2018
comment
@WesWilliams хороший комментарий, но это ключ, который string не String, и у меня нет проблем с кастомным ключом. У меня проблема со значением Object. Кроме того, для сериализации проблема возникает во время компиляции, я не могу добраться до времени выполнения. Наконец, да, кажется ли проблема с PDX. Для REST нам нужен PDX, но не для объекта внутреннего домена, то есть, если внутренний объект никогда не будет использоваться в емкости REST ... хм   -  person rupweb    schedule 05.02.2018


Ответы (2)


Я рекомендую вам удалить «read-serialized = true» и удалить проверку типа для IPdxInstance. У вас все еще могут быть объекты PDX в вашем регионе без read-serialized = true. Вам действительно нужен сам десериализованный объект домена в обратном вызове, а не экземпляр PDX. Отключение сериализации для чтения выполнит это и вернет вам десериализованный объект домена в методе AfterCreate.

Примечание. Приведенная выше рекомендация основана на том факте, что вы используете клиент .NET, а .NET выдает ошибку компиляции. Этого не происходит с клиентами Java. Это немного озадачивает, почему взаимодействие .NET делает это.

К вашему сведению, хорошо известно, что регион может содержать либо экземпляр PDX, либо объект домена в регионе, где используется PDX. Это сделано для повышения производительности. Первичный узел может хранить объект домена в форме, отличной от PDX, чтобы избежать затрат на сериализацию, но в версии PDX на вторичном сервере. Вот почему клиентам всегда нужно проверять тип, прежде чем работать с экземпляром.

Да, я понял, что эта строка была вашим ключом, но моим ключевым вопросом было то, используете ли вы собственный клиент или нет. Строчная буква «s» была ключом к разгадке.

person Wes Williams    schedule 06.02.2018
comment
Да, с использованием собственного клиента .Net. Также для PDX установлено значение true, потому что это требование REST. - person rupweb; 04.07.2018
comment
Итак, я полагаю, что регионы с включенным REST могут быть PDX, а регионы без REST не могут быть! - person rupweb; 04.07.2018

За программирование вашего приложения для использования экземпляров PDX региона может содержать объекты или объекты, обернутые PDX. Для первых работает кастинг через object. Поэтому мне нужно было написать:

object o = ev.NewValue;
if (o.GetType().Name.Equals("PdxInstanceImpl")) 
{
  PdxInstance myPdx = (PdxInstance)o;
  MyObject m = (MyObject)myPdx.GetObject();

  string s = m.MyString;
  decimal d = m.MyDecimal;
}
else
{
  MyObject m = (MyObject)o;

  string s = m.MyString;
  decimal d = m.MyDecimal;
}
person rupweb    schedule 11.06.2018