<h:selectonemenu>和来自hibernate的延迟加载</h:selectonemenu>

时间:2011-05-31 15:49:28

标签: hibernate jsf jsf-2 lazy-loading

在我的JSF应用程序中,我有一段非常简单的代码。我希望用户从<h:selectOneMenu>中的集合中选择一个值:

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

#{bean.value}的类型为Region#{dao.valuesFromDb}会返回Regions的列表。问题是,bean中的Region是从hibernate延迟加载的,它将它包装在一些包装器中,类看起来像my.package.Region_$$_javassist_15@25183

如果#{bean.value}设置了一些值,则应在页面上预选它,如果它在值列表中(#{dao.valuesFromDb})。问题是由equals方法检查,该方法返回false,因为类型不同。

如何解决这个问题?是否有可能强制JSF不使用equals,但不知何故自己处理这种比较?覆盖equals所以忽略类型是恕我直言,这是非常糟糕的主意,因为它可以打破equals对称性。

3 个答案:

答案 0 :(得分:0)

在这种情况下,我会急切地在Region中抓取bean来完全避免这个问题。

使用equals()进行填充将导致代码远不如简单地获取JSF想要进行比较的信息。正如你所指出的那样,它可能会产生意想不到的后果。

答案 1 :(得分:0)

我们决定在Override'equals'方法中解决此问题。重要的技巧是永远不要在equals方法中直接引用外部对象的属性,但总是使用getter。然后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) && (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;
}

答案 2 :(得分:0)

您可以通过调用转发到视图的操作(控制器)中的Region getter来预加载bean,而不是将获取类型更改为EAGER。即:只需调用bean.getRegion()方法。

这样你就不会得到LazyInitializationException(如果那是你得到的)。