и отложенная загрузка из гибернации

#hibernate #jsf #jsf-2 #lazy-loading

#спящий режим #jsf #jsf-2 #отложенная загрузка

Вопрос:

В моем приложении JSF у меня есть довольно простой фрагмент кода. Я хочу, чтобы пользователь выбрал одно значение из коллекции в <h:selectOneMenu> :

 <h:selectOneMenu value="#{bean.value}">
  <f:selectItems value="#{dao.valuesFromDb}" />
</h:selectOneMenu>
  

#{bean.value} имеет тип Region и #{dao.valuesFromDb} возвращает список Regions . Проблема в том, Region что в bean происходит отложенная загрузка из гибернации, которая оборачивает его в некоторую оболочку, класс выглядит как my.package.Region_$$_javassist_15@25183 .

Если #{bean.value} установлено какое-либо значение, оно должно быть предварительно выбрано на странице, если оно есть в списке значений ( #{dao.valuesFromDb} ). Проблема в том, что оно проверяется equals методом, который возвращает false , потому что типы разные.

Как решить эту проблему? Можно ли заставить JSF не использовать equals , но как-то обработать это сравнение самостоятельно? Переопределять, equals чтобы он игнорировал тип, ИМХО, действительно плохая идея, поскольку это может нарушить equals симметрию.

Ответ №1:

В этом случае я бы вообще избежал проблемы, с готовностью загрузив Region в bean .

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

Комментарии:

1. Я просто не могу. У нас много зависимых объектов, и мы только что превысили лимит соединений в одном запросе. Нам пришлось изменить некоторую ускоренную загрузку на отложенную.

2. Интересная проблема. Когда у меня возникали подобные проблемы (глубокий график), я отдельно увлажнял связанные объекты и просто устанавливал их в целевой компонент. Мне пришлось сделать это, чтобы избежать декартовых объединений из-за нескольких коллекций.

3. у нас также была некоторая проблема с декартовыми соединениями. Можете ли вы поделиться какой-нибудь ссылкой, объясняющей это?

4. Вы можете начать с документации по гибернации. Раздел 14.3 включает инструкции «Возможно создать декартово произведение путем объединения нескольких коллекций в запросе, поэтому будьте осторожны в этом случае. Объединение нескольких ролей коллекции может привести к неожиданным результатам при сопоставлении пакетов, поэтому при формулировании запросов в этом случае рекомендуется проявлять осторожность «. Это соответствует моему опыту и часто требует много проб и ошибок, чтобы найти правильное решение. docs.jboss.org/hibernate/core/3.3/reference/en/html /…

Ответ №2:

Мы решили решить эту проблему с помощью наших методов переопределения ’equals’. Важный трюк заключается в том, чтобы никогда не ссылаться на атрибуты внешнего объекта непосредственно в методе equals, но всегда использовать методы получения. Затем Hibernate, похоже, извлекает правильные значения из объекта javassist.

В вашем случае метод Region equals должен выглядеть примерно так:

 @Override
public boolean equals(Object obj) {
    if (this == obj) {return true;}
    if (obj == null) {return false;}
    if (!(obj instanceof Region)) {return false;}

    Region region = (Region) obj;

    if ((name == null) amp;amp; (region.getName() != null)) {return false;}  // Do NOT use 'region.name' here
    else if (!name.equals(region.getName())) {return false;}           // Do NOT use 'region.name' here
    return true;
}
  

Ответ №3:

Вместо изменения типа выборки на EAGER вы можете предварительно загрузить компонент, вызвав Region средство получения в действии (контроллера), которое перенаправляет в ваше представление. Т.е. просто вызовите bean.getRegion() метод.

Таким образом, вы не получите исключение LazyInitializationException (если это то, что вы получаете).