2016-02-12 3 views
-2

Этот вопрос порожден от this ObjectDB forum posting, в надежде, что более широкое сообщество JPA сможет предложить некоторые понимание. Некоторые аспекты могут быть специфическими для реализации ObjectDB в JPAJava: JPA: ObjectDB: pre-detach loading: почему поиск по «навигации и доступу» иногда не работает, если оператор

ObjectDB-2.6.3_04 JDK1.7 вариант VM во время выполнения: -javaagent: Библиотека/objectdb.jar

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

Я использую предварительную отгрузку после em.find (id), потому что просто опираясь на JPA-аннотации, который является подходом «один размер подходит всем», не отвечает моим потребностям во всех ситуациях. Я могу настроить сущность-запрос @EJB с помощью определенного загрузчика, который после выполнения em.find (id) выполняет выбранные операции (при посещении загруженного управляемого объекта) для загрузки и извлечения желаемых значений.

В дополнение к постоянным полям мои сущности имеют методы вычисления переходных процессов, и их вызов при загрузке перед отсоединением должен (и обычно) загружать все необходимое для вычисления временного экспертного системного значения, которое затем должно быть последовательно переконфигурировано, вычисляется после отсоединения и использования в веб-интерфейсе JSF (далее не показано).

Я не буду давать слишком много информации о классах сущностей, я продемонстрирую эту проблему я испытываю первый, но вы должны знать, что ниже:

  • LightingZone подкласс объект блок

  • Блок имеет свойство 'present', которое представляет собой «глубокую» булевую флагов BooleanValue. Это @OneToOne с явным LAZY fetch.

  • Объект BooleanValue обертывает простое значение «Boolean property».

  • A LightingZone имеет свойство «v_NLA», которое является «глубокой» оболочкой Float-значения для объекта FloatQuantity. Это @OneToOne с явным LAZY fetch.

  • Объект FloatQuantity обертывает простое значение свойства Float.

  • (Кроме того, getL_LightingZone() ниже аа общий список оберточной объект, со списком LightingZone доступ через getL_LightingZone(). GetEls(). Это не играет никакой роли в возникшей проблеме.)

«настоящее» из блока объекта в @OneToOne объектного переменная является BooleanValue с:

@Entity 
public class BooleanValue extends Value 
{ 

public BooleanValue() { 
} 

private Boolean value; 
public Boolean getValue() { 
    return value; 
} 
public void setValue(Boolean value) { 
    this.value = value; 
} 
... 

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

И сущность Блок имеет:

private BooleanValue present; 

@OneToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY) 
public BooleanValue getPresent() { 
    return present; 
} 

public void setPresent(BooleanValue present) { 
    this.present = present; 
} 

Это не обязательно должно принести = FetchType.LAZY (если вы установите оставить его по умолчанию выборки = FetchType.EAGER проблема сообщается здесь равна нулю), но по соображениям производительности (и для демонстрации проблемы, описанной здесь) это fetch = FetchType.LAZY (что указывает ObjectDB).

Следующая из моей реальной сети не удается предварительно снять нагрузку, он не в состоянии загрузить тест в указанный если заявление:

@Transient 
public Float getNLA_m2_LightingZone() { 

Float sum = 0f; 
if (getL_LightingZone() != null && getL_LightingZone().getEls() != null) { 
    for (LightingZone lz : getL_LightingZone().getEls()) { 
     if (lz.getPresent().getValue() != null && lz.getPresent().getValue()) { //FAILS TO LOAD getPresent().getValue() 

      //THIS IS NEVER REACHED, ALTHOUGH IN FACT lz.present.value IS true IN THE DATABASE 
      //lz.getPresent().getValue has NOT loaded ok for the test. 

      Float area = lz.getV_NLA().getValue(); 
      if (area != null) { 
       sum += area; 
      } else { 
       return null;//POLICY 
      } 
     } 
    } 
    return sum; 
} else { 
    return null; 
} 
} 

Но странно (для меня по крайней мере) это работает, сохраняя тест во временной переменной:.!.

test = lz.getPresent().getValue() != null && lz.getPresent().getValue(); 
if (test) { 
    // TEST NOW PASSES FINE: lz.getPresent().getValue has INDEED loaded ok for the test. 
Float area = lz.getV_NLA().getValue(); 

Есть некоторые другие вещи, которые также работают, если они используются, прежде чем если (lz.getPresent() ПолучитьЗначение() = нуль & & lz.getPresent() ПолучитьЗначение()):

  • Запись значения lz.getPresent(). GetValue() (или отправка его в System.out).

  • В противном случае вы получите некоторое надуманное использование lz.getPresent(). GetValue() - перед оператором if - что компилятор не удалит.

Это не работает (не хватает) до того, как если тест заявление:.

  • Просто позвонив lz.getPresent() ПолучитьЗначение() где-то, но не используя результат как-то (компилятор просто удаляет его, чтобы загрузка была запущена, его нужно каким-то образом сохранить в переменной, которая в конечном итоге используется ИЛИ используется только для ведения журнала или вывода, подтвержденной с помощью javap -c).

  • «Прикосновение» к id с lz.getPresent(). GetId() перед тегом утверждения if.

Это должно быть обернутое булево значение, и оно должно быть снаружи и до того, как это указано, если выполняется проверка оператора.

Я очень тщательно (не показано здесь) также исследовал состояния нагрузки ObjectDB с использованием Persistence.persistenceUtil() до и после этого проблемного оператора if и соответствует тому, что указано выше. «Lz.present.value» и «lz.v_NLA.value» являются нулевыми и НЕ загружаются перед проблематичным оператором if, а после этого «lz.present.value» загружается (и true), в тех случаях, когда он проходит if вообще (поскольку, например, используется временный держатель «test»).

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

@Transient 
public Float getComputed() { 
    Float val = 0f; 
    if (getL_InnerBlock() != null && getL_InnerBlock().getEls() != null) { 
     for (InnerBlock ib : getL_InnerBlock().getEls()) { 

      //ObjectDB PersistenceUtil claims neither ib.present.value nor ib.present.id are loaded. 

      if (ib.getPresent().getValue() != null && ib.getPresent().getValue()) { 
       //ObjectDB PersistenceUtil claims present.value now loaded.   
       if (f == null) { 
        return null; 
       } else { 
        val += f; 
       } 
      } 
     } 
     return val; 
    } else { 
     return null; 
    } 

}

Это тестовая версия не страдает от тех же проблем, она прекрасно работает без каких-либо «трогательной нагрузки» трюков, хотя Соответственно, если утверждение очевидно идентично.

Таким образом, полный ответ на этот вопрос/проблему объясняет, почему трюк с предварительной загрузкой и хранением lz.present.value перед оператором if может потребоваться в одном случае, но не в другом (в другом слова, какая точка различия может быть, что я должен проверить).

В идеале, я хочу воспроизвести проблему в тестовом приложении, чтобы понять ее полностью.

Мне понадобилось время, чтобы наконец найти/идентифицировать эту проблему, поскольку я не думал, что выполнение доступа к загрузке внутри оператора if может иметь значение (и в конце концов это не вызвало проблем в приложении для мини-теста). Я тщетно пытался найти любую точку различия между настоящим веб-приложением и мини-тестовым приложением, теперь я действительно бамбук (следовательно, это подробное размещение форума).

Для смелых, имейте в виду, что для такого рода проблемы, используя отладчик не ответ (по крайней мере, прогуливаясь с отладчиком NetBeans не поможет мне, как каждый раз, когда вы проверяете переменную она вызывает загрузку он, предотвращая обнаружение реальной проблемы.) Аналогичным образом, использование журнала отладки также может инициировать загрузку. Это кошка Шредингера JPA.

ответ

0

Я считаю это обходным, а не вполне удовлетворительным ответом. поддержка

ObjectDB уже услужливо рассмотрел это дело и предложил мне попробовать использовать post-compile enhancement как Ant задачи в build.xml, а не полагаться на Load Time (Java Agent) Enhancement с этой опцией VM:

-javaagent:lib/objectdb.jar 

Этот агент не повышает скомпилированные файлы классов обратно в/build/web/WEB-INF/classes, он просто увеличивает их, как загруженные в JVM (в памяти).

Это не означает (согласно поддержке ObjectDB), чтобы иметь значение, но это определенно имеет место в моей операционной среде (при развертывании веб-приложения до Glassfish4.1), и я встречал другие тонкие различия в других местах в других случаях. В любом случае сообщаемая проблема исчезла, когда я использовал пост-компиляцию Ant-задачи.

Должна быть точка различия, но она еще не определена.

 Смежные вопросы

  • Нет связанных вопросов^_^