#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 (если это то, что вы получаете).