Hibernate Proxy Problem
I'm sorry to ask such a basic question but I could not find a clear answer in others' questions:
I have a class Foo
public class Foo {
private Integer id;
private String name;
private Bar bar;
// getters and setters
}
And another class Bar
public class Bar {
private Integer id;
private String name;
private Set<Foo> foos;
// getters and setters
}
I have a ManagedBean
which has a ManagedProperty
like this:
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();
}
}
}
}
And in my facelet I try to show the data this开发者_开发知识库way:
<h:outputText value="#{fooBean.foo.bar.name}" />
Which doesn't work! but If I add bar.getName()
to my initialize method (after loading the bar) it works fine!
Why? And what is a best practice alternative?
add
lazy="false"
for the name property in your hibernate mapping xml.
The problem is that you are using
session.load(...)
This method assumes that the entity exist. So it does not have to query the database to check and can simply return a proxy that will load the entity later. If you call a Getter method of the Bar
object you will initialize the proxy and you can make other calls later without database access.
If you use
session.get(...)
this should not happen, because Hibernate will get the entity from the database immediately to check if it exists and does not return a proxy.
You can do these:
- Use eager initialization in your schema (if you use annotations then use 'fetch = FetchType.EAGER'), this defines that everytime a Foo instance is retreived from the DB Foo.bar will be fetched.
- Write a jpa query which tells the API that foo.bar should be fetched in this query, something like this: 'From Foo foo join fetch foo.bar'
The first option is global, the second fetches the foo.bar for that query.
精彩评论