Hibernate代理问题

时间:2011-01-11 15:41:29

标签: java hibernate jsf jsf-2 lazy-loading

我很遗憾地提出这样一个基本问题,但我在其他问题上找不到明确答案:

我有一个班级Foo

public class Foo {
  private Integer id;
  private String name;
  private Bar bar;
  // getters and setters
}

另一个班级Bar

public class Bar {
  private Integer id;
  private String name;
  private Set<Foo> foos;

  // getters and setters 
}

我有ManagedBean,其ManagedProperty像这样:

public class FooBean {
 @ManagedProperty(value = "{param.barId}"
 private Integer barId;
 private Bar bar;
 private Foo foo;

 public FooBean() {
 }

 @PostConstruct
 public void initialize() {
  SessionFactory factory = new Configuration().configure().buildSessionFactory();   
    if barId != null) {
      foo = new Foo();

      Session session = factory.openSession();

      try {
        session.beginTransaction();

        bar = (Bar) session.load(Bar.class, barId);        

        foo.setBar(bar);

        session.getTransaction().commit();
      } catch (Exception ex) {
        Transaction tx = session.getTransaction();
        if (tx.isActive()) {
          tx.rollback();
        }                
      } finally {
        session.close();
      }
    }
 }
}

在我的脸上,我试着以这种方式显示数据:

<h:outputText value="#{fooBean.foo.bar.name}" />

哪个不起作用!但如果我将bar.getName()添加到我的初始化方法(加载栏后),它可以正常工作! 为什么?什么是最佳实践替代方案?

3 个答案:

答案 0 :(得分:3)

添加

lazy="false"

表示hibernate mapping xml中的name属性。

答案 1 :(得分:3)

问题是您正在使用

session.load(...)

此方法假定实体存在。因此,它不必查询要检查的数据库,只需返回稍后将加载实体的代理。如果您调用Bar对象的Getter方法,您将初始化代理,并且您可以在以后进行其他调用而无需数据库访问。

如果您使用

session.get(...)

这不应该发生,因为Hibernate将立即从数据库中获取实体以检查它是否存在并且不返回代理。

答案 2 :(得分:1)

你可以这样做:

  • 在模式中使用急切初始化(如果使用注释然后使用'fetch = FetchType.EAGER'),这将定义每次从DB Foo.bar中获取Foo实例时都会获取。
  • 写一个jpa查询,告诉API在这个查询中应该提取foo.bar,如下所示:'From Foo foo join fetch foo.bar'

第一个选项是global,第二个选项获取该查询的foo.bar。