<h:selectOneMenu> 和从休眠延迟加载



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

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

#{bean.value}的类型为Region#{dao.valuesFromDb}返回Regions的列表。问题是,bean中的Region是从hibernate惰性加载的,hibernate将其封装在某种包装器中,类看起来像my.package.Region_$$_javassist_15@25183

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

如何解决这个问题?是否可以强制JSF不使用equals,而是自己处理这种比较?重写equals从而忽略类型是IMHO非常糟糕的主意,因为它会破坏equals的对称性。

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

与简单地获取JSF想要进行比较的信息相比,使用equals()会导致代码不那么清晰。正如你所指出的,这很可能会产生意想不到的后果。

我们决定在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;
}

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

这样,您就不会得到LazyInitializationException(如果这就是您得到的)。

相关内容

  • 没有找到相关文章

最新更新