Reputation:
I've got a Hibernate object which's properties are all loaded lazy. Most of these properties are other Hibernate objects or PersistentSets.
Now I want to force Hibernate to eager load these properties for just one time.
Of course I could "touch" each of these properties with object.getSite().size()
but maybe there's another way to achieve my goal.
Upvotes: 26
Views: 30293
Reputation: 8771
A decade has passed since this question was asked, but I bumped into this problem as well. I noticed that if you are using Spring, annotating the method with org.springframework.transaction.annotation.Transactional
solves it nicely.
Example
public void doThing(int id) {
Thing thing = loadThing(id);
Stuff stuff = thing.getLazyLoadedStuff();
}
doesn't work, exception thrown. But
@Transactional
public void doThing(int id) {
Thing thing = loadThing(id);
Stuff stuff = thing.getLazyLoadedStuff();
}
works.
Upvotes: 0
Reputation: 9604
This is an old question, but I also wanted to point out the static method Hibernate.initialize
.
Example usage:
Person p = sess.createCriteria(Person.class, id);
Hibernate.initialize(p.getChildren());
The children are now initialized to be used even after the session is closed.
Upvotes: 23
Reputation: 186
3 ways
1.HQL with left join children
2.SetFetchMode after createCriteria
3.Hibernate.initialize
Upvotes: 1
Reputation: 11
For me this works:
Person p = (Parent) sess.get(Person.class, id);
Hibernate.initialize(p.getChildren());
Rather than this:
Person p = sess.createCriteria(Person.class, id);
Hibernate.initialize(p.getChildren());
Upvotes: 1
Reputation: 71
This is slow, because it makes a round trip for every item it needs to initialize, but it gets the job done.
private void RecursiveInitialize(object o,IList completed)
{
if (completed == null) throw new ArgumentNullException("completed");
if (o == null) return;
if (completed.Contains(o)) return;
NHibernateUtil.Initialize(o);
completed.Add(o);
var type = NHibernateUtil.GetClass(o);
if (type.IsSealed) return;
foreach (var prop in type.GetProperties())
{
if (prop.PropertyType.IsArray)
{
var result = prop.GetValue(o, null) as IEnumerable;
if (result == null) return;
foreach (var item in result)
{
RecursiveInitialize(item, completed);
}
}
else if (prop.PropertyType.GetGenericArguments().Length > 0)
{
var result = prop.GetValue(o, null) as IEnumerable;
if (result == null) return;
foreach (var item in result)
{
RecursiveInitialize(item, completed);
}
}
else
{
var value = prop.GetValue(o, null);
RecursiveInitialize(value, completed);
}
}
}
Upvotes: 0
Reputation: 570285
The documentation puts it like this:
You can force the usual eager fetching of properties using
fetch all properties
in HQL.
Upvotes: 7
Reputation: 139921
Dozer works well for this type of thing - you can ask Dozer to map the object to another instance of the same class, and Dozer will visit all objects reachable from the current object.
See this answer to a similar question and my answer to another related question for more details.
Upvotes: 3
Reputation: 274532
According to the hibernate docs, you should be able to disable lazy property loading by setting the lazy
attribute on your particular property mappings:
<class name="Document">
<id name="id">
<generator class="native"/>
</id>
<property length="50" name="name" not-null="true"/>
<property lazy="false" length="200" name="summary" not-null="true"/>
<property lazy="false" length="2000" name="text" not-null="true"/>
</class>
Upvotes: -1