Get a Reference implicitly
Entity Beans returned by a query will have Reference/Proxy objects.
Note: From an Object graph perspective
they are the 'leaves' of the tree.
FindById find = new FindById(Bug.class, 1);
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();
The resulting SQL from the above is three separate queries. The last two are the
result of the lazy loading of userLogged and details.
<sql summary='[app.data.Bug]'>
SELECT b.id, b.body, b.cretime, b.duplicate_of, b.fixed_version,
b.reported_version, b.resolution, b.title, b.updtime,
b.priority_code, b.product_id, b.status_code, b.type_code,
b.user_assigned_id, b.user_logged_id
FROM b_bug b
WHERE b.id = ?
</sql>
<sql summary='[app.data.User]'>
SELECT u.id, u.cookie_login, u.cretime, u.email, u.error_count,
u.last_login, u.name, u.pwd, u.reset_code, u.reset_time,
u.salt, u.updtime, u.status_code
FROM s_user u
WHERE u.id = ?
</sql>
<sql summary='[app.data.BugDetail]'>
SELECT d.id, d.body, d.cretime, d.post_date, d.title, d.updtime,
d.bug_id, d.user_id
FROM b_bug_detail d
WHERE bug_id = ?
</sql>
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();
The resulting SQL is:
<sql summary='[app.data.Bug, userLogged] +many[details]'>
SELECT b.id, b.body, b.cretime, b.duplicate_of, b.fixed_version,
b.reported_version, b.resolution, b.title, b.updtime,
b.priority_code, b.product_id, b.status_code, b.type_code,
b.user_assigned_id
, cu.id, cu.cookie_login, cu.cretime, cu.email, cu.error_count,
cu.last_login, cu.name, cu.pwd, cu.reset_code, cu.reset_time,
cu.salt, cu.updtime
, ed.id, ed.body, ed.cretime, ed.post_date, ed.title,
ed.updtime, ed.bug_id, ed.user_id
FROM b_bug b
LEFT OUTER JOIN s_user cu ON b.user_logged_id = cu.id
LEFT OUTER JOIN b_bug_detail ed ON b.id = ed.bug_id
WHERE b.id = ?
</sql>
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.
|