Lazy Loading Introduction

Lazy Loading is when a Reference (also called Proxy) Bean or Collection is populated automatically by
a query.

For a List Set or Map lazy loading is provided by the matching BeanList BeanSet and BeanMap objects
found in com.avaje.ebean.collection. These are wrappers around the underlying List Set or Maps.
If a BeanList is a Reference/Proxy then its underlying list is null but it has a Find object that
can be used to 'lazy load' the list.
Any methods called on BeanList such as size() hashCode() iterator() get() etc will automatically
result in a query being executed fetching the underlying list.

For Lazy Loading on individual Entity Beans this is achieved by method interception (AOP). The
appropriate 'getter' and 'setter' methods are intercepted and lazy loading is invoked as appropriate.

Get a Reference explicitly

// Get a reference(proxy) explicitly
Bug bugRef = (Bug)Ebean.getReference(Bug.class, 1);
// This does NOT invoke a lazy load as its the Id
Integer bugId = bugRef.getId();
// This WILL invoke the lazy load query loading the data
// into bugRef before returning the title
String title = bugRef.getTitle();

The way this works is that the appropriate 'getter' and 'setter' methods are intercepted.
The getTitle() method invokes the 'lazy loading query' and the data is loaded into the butRef instance
before returning the title.

Id and Transient properties do not invoke lazy loading.

Before continuing I'd like to point out that these two methods below are exactly the same.
The reason you would want to use the FindById object is that it gives you additional options for
the query including whether to use caching and what associations to include in the query.

setInclude()

If you knew that you where going to get the userLogged and details information then you
would likely be better off including them in the original query. The next example uses
the find.setInclude() method to specify that we want to also get that information.

FindById find = new FindById(Bug.class, 1);
// also include these associations in the query
find.setInclude("userLogged; details; ");
Bug bug = (Bug)Ebean.find(find);
// user is a reference/proxy
User user = bug.getUserLogged();
// details is also a reference/proxy
List details = bug.getDetails();
// this invokes a query for the user
String name = user.getName();
// this invokes a query for the details
int size = details.size();

In general, if you know you are going to use the information then you should
probably look to include it in the query.

Negative: including a OneToMany(or ManyToMany) repeats 'master'

In the example above we included the 'details' which is a OneToMany association.
If you take the sql and execute it you will note that the bug and userLogged information
(columns prefixed with b. and cu.) are repeated for each row in the
bug details (b_bug_detail) table.

That is, for 'master detail' queries (where a associated OneToMany or ManyToMany is included
in the query) the benefit of getting the 'details' in the same query as the 'master' needs
to be balanced against the cost of 'master' columns being repeated.

Note: Only one OneToMany(or ManyToMany) can be included

Also note that only one OneToMany or ManyToMany association is allowed to be included in the
query. The reason is that including more than one would result in a cartesian product and that
is likely to be unwise due to cost.

For the Bug entity bean it has two OneToMany associations in Details and Attachments. You could include
the Details or the Attachments but not both in a single query.